xref: /openbmc/linux/drivers/acpi/ec.c (revision fac59652993f075d57860769c99045b3ca18780d)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3a8d4fc22SLv Zheng  *  ec.c - ACPI Embedded Controller Driver (v3)
41da177e4SLinus Torvalds  *
5a8d4fc22SLv Zheng  *  Copyright (C) 2001-2015 Intel Corporation
6a8d4fc22SLv Zheng  *    Author: 2014, 2015 Lv Zheng <lv.zheng@intel.com>
74a3f6b5bSLv Zheng  *            2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
84a3f6b5bSLv Zheng  *            2006       Denis Sadykov <denis.m.sadykov@intel.com>
94a3f6b5bSLv Zheng  *            2004       Luming Yu <luming.yu@intel.com>
104a3f6b5bSLv Zheng  *            2001, 2002 Andy Grover <andrew.grover@intel.com>
114a3f6b5bSLv Zheng  *            2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
124a3f6b5bSLv Zheng  *  Copyright (C) 2008      Alexey Starikovskiy <astarikovskiy@suse.de>
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
157c6db4e0SAlexey Starikovskiy /* Uncomment next line to get verbose printout */
16d772b3b3SMárton Németh /* #define DEBUG */
1716a26e85SLan Tianyu #define pr_fmt(fmt) "ACPI: EC: " fmt
18d772b3b3SMárton Németh 
191da177e4SLinus Torvalds #include <linux/kernel.h>
201da177e4SLinus Torvalds #include <linux/module.h>
211da177e4SLinus Torvalds #include <linux/init.h>
221da177e4SLinus Torvalds #include <linux/types.h>
231da177e4SLinus Torvalds #include <linux/delay.h>
24451566f4SDmitry Torokhov #include <linux/interrupt.h>
25837012edSAlexey Starikovskiy #include <linux/list.h>
267c6db4e0SAlexey Starikovskiy #include <linux/spinlock.h>
275a0e3ad6STejun Heo #include <linux/slab.h>
2810a08fd6SRafael J. Wysocki #include <linux/suspend.h>
298b48463fSLv Zheng #include <linux/acpi.h>
30eb27cae8SLen Brown #include <linux/dmi.h>
318b48463fSLv Zheng #include <asm/io.h>
321da177e4SLinus Torvalds 
331195a098SThomas Renninger #include "internal.h"
341195a098SThomas Renninger 
351da177e4SLinus Torvalds #define ACPI_EC_CLASS			"embedded_controller"
361da177e4SLinus Torvalds #define ACPI_EC_DEVICE_NAME		"Embedded Controller"
37837012edSAlexey Starikovskiy 
38703959d4SDenis M. Sadykov /* EC status register */
391da177e4SLinus Torvalds #define ACPI_EC_FLAG_OBF	0x01	/* Output buffer full */
401da177e4SLinus Torvalds #define ACPI_EC_FLAG_IBF	0x02	/* Input buffer full */
41dd43de20SLv Zheng #define ACPI_EC_FLAG_CMD	0x08	/* Input buffer contains a command */
42451566f4SDmitry Torokhov #define ACPI_EC_FLAG_BURST	0x10	/* burst mode */
431da177e4SLinus Torvalds #define ACPI_EC_FLAG_SCI	0x20	/* EC-SCI occurred */
444350933aSAlexey Starikovskiy 
451d68d261SLv Zheng /*
461d68d261SLv Zheng  * The SCI_EVT clearing timing is not defined by the ACPI specification.
471d68d261SLv Zheng  * This leads to lots of practical timing issues for the host EC driver.
481d68d261SLv Zheng  * The following variations are defined (from the target EC firmware's
491d68d261SLv Zheng  * perspective):
501d68d261SLv Zheng  * STATUS: After indicating SCI_EVT edge triggered IRQ to the host, the
511d68d261SLv Zheng  *         target can clear SCI_EVT at any time so long as the host can see
521d68d261SLv Zheng  *         the indication by reading the status register (EC_SC). So the
531d68d261SLv Zheng  *         host should re-check SCI_EVT after the first time the SCI_EVT
541d68d261SLv Zheng  *         indication is seen, which is the same time the query request
551d68d261SLv Zheng  *         (QR_EC) is written to the command register (EC_CMD). SCI_EVT set
561d68d261SLv Zheng  *         at any later time could indicate another event. Normally such
571d68d261SLv Zheng  *         kind of EC firmware has implemented an event queue and will
581d68d261SLv Zheng  *         return 0x00 to indicate "no outstanding event".
591d68d261SLv Zheng  * QUERY: After seeing the query request (QR_EC) written to the command
601d68d261SLv Zheng  *        register (EC_CMD) by the host and having prepared the responding
611d68d261SLv Zheng  *        event value in the data register (EC_DATA), the target can safely
621d68d261SLv Zheng  *        clear SCI_EVT because the target can confirm that the current
631d68d261SLv Zheng  *        event is being handled by the host. The host then should check
641d68d261SLv Zheng  *        SCI_EVT right after reading the event response from the data
651d68d261SLv Zheng  *        register (EC_DATA).
661d68d261SLv Zheng  * EVENT: After seeing the event response read from the data register
671d68d261SLv Zheng  *        (EC_DATA) by the host, the target can clear SCI_EVT. As the
681d68d261SLv Zheng  *        target requires time to notice the change in the data register
691d68d261SLv Zheng  *        (EC_DATA), the host may be required to wait additional guarding
701d68d261SLv Zheng  *        time before checking the SCI_EVT again. Such guarding may not be
711d68d261SLv Zheng  *        necessary if the host is notified via another IRQ.
721d68d261SLv Zheng  */
731d68d261SLv Zheng #define ACPI_EC_EVT_TIMING_STATUS	0x00
741d68d261SLv Zheng #define ACPI_EC_EVT_TIMING_QUERY	0x01
751d68d261SLv Zheng #define ACPI_EC_EVT_TIMING_EVENT	0x02
761d68d261SLv Zheng 
77703959d4SDenis M. Sadykov /* EC commands */
783261ff4dSAlexey Starikovskiy enum ec_command {
793261ff4dSAlexey Starikovskiy 	ACPI_EC_COMMAND_READ = 0x80,
803261ff4dSAlexey Starikovskiy 	ACPI_EC_COMMAND_WRITE = 0x81,
813261ff4dSAlexey Starikovskiy 	ACPI_EC_BURST_ENABLE = 0x82,
823261ff4dSAlexey Starikovskiy 	ACPI_EC_BURST_DISABLE = 0x83,
833261ff4dSAlexey Starikovskiy 	ACPI_EC_COMMAND_QUERY = 0x84,
843261ff4dSAlexey Starikovskiy };
85837012edSAlexey Starikovskiy 
865c406412SAlexey Starikovskiy #define ACPI_EC_DELAY		500	/* Wait 500ms max. during EC ops */
87703959d4SDenis M. Sadykov #define ACPI_EC_UDELAY_GLK	1000	/* Wait 1ms max. to get global lock */
88d8d031a6SLv Zheng #define ACPI_EC_UDELAY_POLL	550	/* Wait 1ms for EC transaction polling */
89ad332c8aSKieran Clancy #define ACPI_EC_CLEAR_MAX	100	/* Maximum number of events to query
90ad332c8aSKieran Clancy 					 * when trying to clear the EC */
91e1191bd4SLv Zheng #define ACPI_EC_MAX_QUERIES	16	/* Maximum number of parallel queries */
92703959d4SDenis M. Sadykov 
93080e412cSAlexey Starikovskiy enum {
94750f628bSLv Zheng 	EC_FLAGS_QUERY_ENABLED,		/* Query is enabled */
954446abc9SDaniel Drake 	EC_FLAGS_EVENT_HANDLER_INSTALLED,	/* Event handler installed */
960e1affe4SLv Zheng 	EC_FLAGS_EC_HANDLER_INSTALLED,	/* OpReg handler installed */
97ab4620f5SHans de Goede 	EC_FLAGS_EC_REG_CALLED,		/* OpReg ACPI _REG method called */
984446abc9SDaniel Drake 	EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
99ad479e7fSLv Zheng 	EC_FLAGS_STARTED,		/* Driver is started */
100ad479e7fSLv Zheng 	EC_FLAGS_STOPPED,		/* Driver is stopped */
1014446abc9SDaniel Drake 	EC_FLAGS_EVENTS_MASKED,		/* Events masked */
1021da177e4SLinus Torvalds };
1036ffb221aSDenis M. Sadykov 
104f92fca00SLv Zheng #define ACPI_EC_COMMAND_POLL		0x01 /* Available for command byte */
105f92fca00SLv Zheng #define ACPI_EC_COMMAND_COMPLETE	0x02 /* Completed last byte */
106f92fca00SLv Zheng 
1077a18e96dSThomas Renninger /* ec.c is compiled in acpi namespace so this shows up as acpi.ec_delay param */
1087a18e96dSThomas Renninger static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
1097a18e96dSThomas Renninger module_param(ec_delay, uint, 0644);
1107a18e96dSThomas Renninger MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
1117a18e96dSThomas Renninger 
112e1191bd4SLv Zheng static unsigned int ec_max_queries __read_mostly = ACPI_EC_MAX_QUERIES;
113e1191bd4SLv Zheng module_param(ec_max_queries, uint, 0644);
114e1191bd4SLv Zheng MODULE_PARM_DESC(ec_max_queries, "Maximum parallel _Qxx evaluations");
115e1191bd4SLv Zheng 
11615de603bSLv Zheng static bool ec_busy_polling __read_mostly;
11715de603bSLv Zheng module_param(ec_busy_polling, bool, 0644);
11815de603bSLv Zheng MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
11915de603bSLv Zheng 
12015de603bSLv Zheng static unsigned int ec_polling_guard __read_mostly = ACPI_EC_UDELAY_POLL;
12115de603bSLv Zheng module_param(ec_polling_guard, uint, 0644);
12215de603bSLv Zheng MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in polling modes");
12315de603bSLv Zheng 
1243cb02aebSLv Zheng static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
1251d68d261SLv Zheng 
126a520d52eSFeng Tang /*
127a520d52eSFeng Tang  * If the number of false interrupts per one transaction exceeds
128a520d52eSFeng Tang  * this threshold, will think there is a GPE storm happened and
129a520d52eSFeng Tang  * will disable the GPE for normal transaction.
130a520d52eSFeng Tang  */
131a520d52eSFeng Tang static unsigned int ec_storm_threshold  __read_mostly = 8;
132a520d52eSFeng Tang module_param(ec_storm_threshold, uint, 0644);
133a520d52eSFeng Tang MODULE_PARM_DESC(ec_storm_threshold, "Maxim false GPE numbers not considered as GPE storm");
134a520d52eSFeng Tang 
13569cace6eSwangzhitong static bool ec_freeze_events __read_mostly;
13639a2a2aaSLv Zheng module_param(ec_freeze_events, bool, 0644);
13739a2a2aaSLv Zheng MODULE_PARM_DESC(ec_freeze_events, "Disabling event handling during suspend/resume");
13839a2a2aaSLv Zheng 
13976380636SRafael J. Wysocki static bool ec_no_wakeup __read_mostly;
14076380636SRafael J. Wysocki module_param(ec_no_wakeup, bool, 0644);
14176380636SRafael J. Wysocki MODULE_PARM_DESC(ec_no_wakeup, "Do not wake up from suspend-to-idle");
14276380636SRafael J. Wysocki 
143837012edSAlexey Starikovskiy struct acpi_ec_query_handler {
144837012edSAlexey Starikovskiy 	struct list_head node;
145837012edSAlexey Starikovskiy 	acpi_ec_query_func func;
146837012edSAlexey Starikovskiy 	acpi_handle handle;
147837012edSAlexey Starikovskiy 	void *data;
148837012edSAlexey Starikovskiy 	u8 query_bit;
14901305d41SLv Zheng 	struct kref kref;
150837012edSAlexey Starikovskiy };
151837012edSAlexey Starikovskiy 
1528463200aSAlexey Starikovskiy struct transaction {
1537c6db4e0SAlexey Starikovskiy 	const u8 *wdata;
1547c6db4e0SAlexey Starikovskiy 	u8 *rdata;
1557c6db4e0SAlexey Starikovskiy 	unsigned short irq_count;
1568463200aSAlexey Starikovskiy 	u8 command;
157a2f93aeaSAlexey Starikovskiy 	u8 wi;
158a2f93aeaSAlexey Starikovskiy 	u8 ri;
1597c6db4e0SAlexey Starikovskiy 	u8 wlen;
1607c6db4e0SAlexey Starikovskiy 	u8 rlen;
161f92fca00SLv Zheng 	u8 flags;
1627c6db4e0SAlexey Starikovskiy };
1637c6db4e0SAlexey Starikovskiy 
16402b771b6SLv Zheng struct acpi_ec_query {
16502b771b6SLv Zheng 	struct transaction transaction;
16602b771b6SLv Zheng 	struct work_struct work;
16702b771b6SLv Zheng 	struct acpi_ec_query_handler *handler;
1684a9af6caSRafael J. Wysocki 	struct acpi_ec *ec;
16902b771b6SLv Zheng };
17002b771b6SLv Zheng 
171eafe7509SRafael J. Wysocki static int acpi_ec_submit_query(struct acpi_ec *ec);
1729aa60f3cSRafael J. Wysocki static void advance_transaction(struct acpi_ec *ec, bool interrupt);
17302b771b6SLv Zheng static void acpi_ec_event_handler(struct work_struct *work);
17474443bbeSLv Zheng 
175a9c30768SRafael J. Wysocki struct acpi_ec *first_ec;
1761195a098SThomas Renninger EXPORT_SYMBOL(first_ec);
177a9c30768SRafael J. Wysocki 
178a9c30768SRafael J. Wysocki static struct acpi_ec *boot_ec;
17969cace6eSwangzhitong static bool boot_ec_is_ecdt;
180f0ac20c3SRafael J. Wysocki static struct workqueue_struct *ec_wq;
181e1191bd4SLv Zheng static struct workqueue_struct *ec_query_wq;
182703959d4SDenis M. Sadykov 
18359f0aa94SLv Zheng static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */
1844370cbf3SZhang Rui static int EC_FLAGS_TRUST_DSDT_GPE; /* Needs DSDT GPE as correction setting */
185b6a3e147SZhang Rui static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
1865423a0cbSAlexey Starikovskiy 
1871da177e4SLinus Torvalds /* --------------------------------------------------------------------------
1883535a3c1SLv Zheng  *                           Logging/Debugging
1893535a3c1SLv Zheng  * -------------------------------------------------------------------------- */
1903535a3c1SLv Zheng 
1913535a3c1SLv Zheng /*
1923535a3c1SLv Zheng  * Splitters used by the developers to track the boundary of the EC
1933535a3c1SLv Zheng  * handling processes.
1943535a3c1SLv Zheng  */
1953535a3c1SLv Zheng #ifdef DEBUG
1963535a3c1SLv Zheng #define EC_DBG_SEP	" "
1973535a3c1SLv Zheng #define EC_DBG_DRV	"+++++"
1983535a3c1SLv Zheng #define EC_DBG_STM	"====="
1993535a3c1SLv Zheng #define EC_DBG_REQ	"*****"
2003535a3c1SLv Zheng #define EC_DBG_EVT	"#####"
2013535a3c1SLv Zheng #else
2023535a3c1SLv Zheng #define EC_DBG_SEP	""
2033535a3c1SLv Zheng #define EC_DBG_DRV
2043535a3c1SLv Zheng #define EC_DBG_STM
2053535a3c1SLv Zheng #define EC_DBG_REQ
2063535a3c1SLv Zheng #define EC_DBG_EVT
2073535a3c1SLv Zheng #endif
2083535a3c1SLv Zheng 
2093535a3c1SLv Zheng #define ec_log_raw(fmt, ...) \
2103535a3c1SLv Zheng 	pr_info(fmt "\n", ##__VA_ARGS__)
2113535a3c1SLv Zheng #define ec_dbg_raw(fmt, ...) \
2123535a3c1SLv Zheng 	pr_debug(fmt "\n", ##__VA_ARGS__)
2133535a3c1SLv Zheng #define ec_log(filter, fmt, ...) \
2143535a3c1SLv Zheng 	ec_log_raw(filter EC_DBG_SEP fmt EC_DBG_SEP filter, ##__VA_ARGS__)
2153535a3c1SLv Zheng #define ec_dbg(filter, fmt, ...) \
2163535a3c1SLv Zheng 	ec_dbg_raw(filter EC_DBG_SEP fmt EC_DBG_SEP filter, ##__VA_ARGS__)
2173535a3c1SLv Zheng 
2183535a3c1SLv Zheng #define ec_log_drv(fmt, ...) \
2193535a3c1SLv Zheng 	ec_log(EC_DBG_DRV, fmt, ##__VA_ARGS__)
2203535a3c1SLv Zheng #define ec_dbg_drv(fmt, ...) \
2213535a3c1SLv Zheng 	ec_dbg(EC_DBG_DRV, fmt, ##__VA_ARGS__)
2223535a3c1SLv Zheng #define ec_dbg_stm(fmt, ...) \
2233535a3c1SLv Zheng 	ec_dbg(EC_DBG_STM, fmt, ##__VA_ARGS__)
2243535a3c1SLv Zheng #define ec_dbg_req(fmt, ...) \
2253535a3c1SLv Zheng 	ec_dbg(EC_DBG_REQ, fmt, ##__VA_ARGS__)
2263535a3c1SLv Zheng #define ec_dbg_evt(fmt, ...) \
2273535a3c1SLv Zheng 	ec_dbg(EC_DBG_EVT, fmt, ##__VA_ARGS__)
228770970f0SLv Zheng #define ec_dbg_ref(ec, fmt, ...) \
229770970f0SLv Zheng 	ec_dbg_raw("%lu: " fmt, ec->reference_count, ## __VA_ARGS__)
2303535a3c1SLv Zheng 
2313535a3c1SLv Zheng /* --------------------------------------------------------------------------
232ad479e7fSLv Zheng  *                           Device Flags
233ad479e7fSLv Zheng  * -------------------------------------------------------------------------- */
234ad479e7fSLv Zheng 
acpi_ec_started(struct acpi_ec * ec)235ad479e7fSLv Zheng static bool acpi_ec_started(struct acpi_ec *ec)
236ad479e7fSLv Zheng {
237ad479e7fSLv Zheng 	return test_bit(EC_FLAGS_STARTED, &ec->flags) &&
238ad479e7fSLv Zheng 	       !test_bit(EC_FLAGS_STOPPED, &ec->flags);
239ad479e7fSLv Zheng }
240ad479e7fSLv Zheng 
acpi_ec_event_enabled(struct acpi_ec * ec)241750f628bSLv Zheng static bool acpi_ec_event_enabled(struct acpi_ec *ec)
242750f628bSLv Zheng {
243750f628bSLv Zheng 	/*
244750f628bSLv Zheng 	 * There is an OSPM early stage logic. During the early stages
245750f628bSLv Zheng 	 * (boot/resume), OSPMs shouldn't enable the event handling, only
246750f628bSLv Zheng 	 * the EC transactions are allowed to be performed.
247750f628bSLv Zheng 	 */
248750f628bSLv Zheng 	if (!test_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
249750f628bSLv Zheng 		return false;
250750f628bSLv Zheng 	/*
25139a2a2aaSLv Zheng 	 * However, disabling the event handling is experimental for late
25239a2a2aaSLv Zheng 	 * stage (suspend), and is controlled by the boot parameter of
25339a2a2aaSLv Zheng 	 * "ec_freeze_events":
25439a2a2aaSLv Zheng 	 * 1. true:  The EC event handling is disabled before entering
25539a2a2aaSLv Zheng 	 *           the noirq stage.
25639a2a2aaSLv Zheng 	 * 2. false: The EC event handling is automatically disabled as
25739a2a2aaSLv Zheng 	 *           soon as the EC driver is stopped.
258750f628bSLv Zheng 	 */
25939a2a2aaSLv Zheng 	if (ec_freeze_events)
26039a2a2aaSLv Zheng 		return acpi_ec_started(ec);
26139a2a2aaSLv Zheng 	else
262750f628bSLv Zheng 		return test_bit(EC_FLAGS_STARTED, &ec->flags);
263750f628bSLv Zheng }
264750f628bSLv Zheng 
acpi_ec_flushed(struct acpi_ec * ec)2659887d22aSLv Zheng static bool acpi_ec_flushed(struct acpi_ec *ec)
2669887d22aSLv Zheng {
2679887d22aSLv Zheng 	return ec->reference_count == 1;
2689887d22aSLv Zheng }
2699887d22aSLv Zheng 
270ad479e7fSLv Zheng /* --------------------------------------------------------------------------
271ca37bfdfSLv Zheng  *                           EC Registers
2727a73e60eSLv Zheng  * -------------------------------------------------------------------------- */
2731da177e4SLinus Torvalds 
acpi_ec_read_status(struct acpi_ec * ec)2746ffb221aSDenis M. Sadykov static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
2751da177e4SLinus Torvalds {
2763ebe08a7SMárton Németh 	u8 x = inb(ec->command_addr);
2777a73e60eSLv Zheng 
2783535a3c1SLv Zheng 	ec_dbg_raw("EC_SC(R) = 0x%2.2x "
2793535a3c1SLv Zheng 		   "SCI_EVT=%d BURST=%d CMD=%d IBF=%d OBF=%d",
280dd43de20SLv Zheng 		   x,
281dd43de20SLv Zheng 		   !!(x & ACPI_EC_FLAG_SCI),
282dd43de20SLv Zheng 		   !!(x & ACPI_EC_FLAG_BURST),
283dd43de20SLv Zheng 		   !!(x & ACPI_EC_FLAG_CMD),
284dd43de20SLv Zheng 		   !!(x & ACPI_EC_FLAG_IBF),
285dd43de20SLv Zheng 		   !!(x & ACPI_EC_FLAG_OBF));
2863ebe08a7SMárton Németh 	return x;
287451566f4SDmitry Torokhov }
2881da177e4SLinus Torvalds 
acpi_ec_read_data(struct acpi_ec * ec)2896ffb221aSDenis M. Sadykov static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
290703959d4SDenis M. Sadykov {
2913ebe08a7SMárton Németh 	u8 x = inb(ec->data_addr);
2927a73e60eSLv Zheng 
293d8d031a6SLv Zheng 	ec->timestamp = jiffies;
2943535a3c1SLv Zheng 	ec_dbg_raw("EC_DATA(R) = 0x%2.2x", x);
2957c6db4e0SAlexey Starikovskiy 	return x;
296703959d4SDenis M. Sadykov }
297703959d4SDenis M. Sadykov 
acpi_ec_write_cmd(struct acpi_ec * ec,u8 command)2986ffb221aSDenis M. Sadykov static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
299703959d4SDenis M. Sadykov {
3003535a3c1SLv Zheng 	ec_dbg_raw("EC_SC(W) = 0x%2.2x", command);
3016ffb221aSDenis M. Sadykov 	outb(command, ec->command_addr);
302d8d031a6SLv Zheng 	ec->timestamp = jiffies;
303703959d4SDenis M. Sadykov }
304703959d4SDenis M. Sadykov 
acpi_ec_write_data(struct acpi_ec * ec,u8 data)3056ffb221aSDenis M. Sadykov static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
306703959d4SDenis M. Sadykov {
3073535a3c1SLv Zheng 	ec_dbg_raw("EC_DATA(W) = 0x%2.2x", data);
3086ffb221aSDenis M. Sadykov 	outb(data, ec->data_addr);
309d8d031a6SLv Zheng 	ec->timestamp = jiffies;
310703959d4SDenis M. Sadykov }
311703959d4SDenis M. Sadykov 
3124625d752SLv Zheng #if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
acpi_ec_cmd_string(u8 cmd)313e34c0e2bSLv Zheng static const char *acpi_ec_cmd_string(u8 cmd)
314e34c0e2bSLv Zheng {
315e34c0e2bSLv Zheng 	switch (cmd) {
316e34c0e2bSLv Zheng 	case 0x80:
317e34c0e2bSLv Zheng 		return "RD_EC";
318e34c0e2bSLv Zheng 	case 0x81:
319e34c0e2bSLv Zheng 		return "WR_EC";
320e34c0e2bSLv Zheng 	case 0x82:
321e34c0e2bSLv Zheng 		return "BE_EC";
322e34c0e2bSLv Zheng 	case 0x83:
323e34c0e2bSLv Zheng 		return "BD_EC";
324e34c0e2bSLv Zheng 	case 0x84:
325e34c0e2bSLv Zheng 		return "QR_EC";
326e34c0e2bSLv Zheng 	}
327e34c0e2bSLv Zheng 	return "UNKNOWN";
328e34c0e2bSLv Zheng }
329e34c0e2bSLv Zheng #else
330e34c0e2bSLv Zheng #define acpi_ec_cmd_string(cmd)		"UNDEF"
331e34c0e2bSLv Zheng #endif
332e34c0e2bSLv Zheng 
333ca37bfdfSLv Zheng /* --------------------------------------------------------------------------
334ca37bfdfSLv Zheng  *                           GPE Registers
335ca37bfdfSLv Zheng  * -------------------------------------------------------------------------- */
336ca37bfdfSLv Zheng 
acpi_ec_gpe_status_set(struct acpi_ec * ec)337d2a2e6ccSRafael J. Wysocki static inline bool acpi_ec_gpe_status_set(struct acpi_ec *ec)
338ca37bfdfSLv Zheng {
339ca37bfdfSLv Zheng 	acpi_event_status gpe_status = 0;
340ca37bfdfSLv Zheng 
341ca37bfdfSLv Zheng 	(void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
342d2a2e6ccSRafael J. Wysocki 	return !!(gpe_status & ACPI_EVENT_FLAG_STATUS_SET);
343ca37bfdfSLv Zheng }
344ca37bfdfSLv Zheng 
acpi_ec_enable_gpe(struct acpi_ec * ec,bool open)345ca37bfdfSLv Zheng static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
346ca37bfdfSLv Zheng {
347ca37bfdfSLv Zheng 	if (open)
348ca37bfdfSLv Zheng 		acpi_enable_gpe(NULL, ec->gpe);
349e1d4d90fSLv Zheng 	else {
350e1d4d90fSLv Zheng 		BUG_ON(ec->reference_count < 1);
351ca37bfdfSLv Zheng 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
352e1d4d90fSLv Zheng 	}
353d2a2e6ccSRafael J. Wysocki 	if (acpi_ec_gpe_status_set(ec)) {
354ca37bfdfSLv Zheng 		/*
355ca37bfdfSLv Zheng 		 * On some platforms, EN=1 writes cannot trigger GPE. So
356ca37bfdfSLv Zheng 		 * software need to manually trigger a pseudo GPE event on
357ca37bfdfSLv Zheng 		 * EN=1 writes.
358ca37bfdfSLv Zheng 		 */
3593535a3c1SLv Zheng 		ec_dbg_raw("Polling quirk");
3602e84ea5aSSebastian Andrzej Siewior 		advance_transaction(ec, false);
361ca37bfdfSLv Zheng 	}
362ca37bfdfSLv Zheng }
363ca37bfdfSLv Zheng 
acpi_ec_disable_gpe(struct acpi_ec * ec,bool close)364ca37bfdfSLv Zheng static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
365ca37bfdfSLv Zheng {
366ca37bfdfSLv Zheng 	if (close)
367ca37bfdfSLv Zheng 		acpi_disable_gpe(NULL, ec->gpe);
368e1d4d90fSLv Zheng 	else {
369e1d4d90fSLv Zheng 		BUG_ON(ec->reference_count < 1);
370ca37bfdfSLv Zheng 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
371ca37bfdfSLv Zheng 	}
372e1d4d90fSLv Zheng }
373ca37bfdfSLv Zheng 
374ca37bfdfSLv Zheng /* --------------------------------------------------------------------------
375ca37bfdfSLv Zheng  *                           Transaction Management
376ca37bfdfSLv Zheng  * -------------------------------------------------------------------------- */
377ca37bfdfSLv Zheng 
acpi_ec_submit_request(struct acpi_ec * ec)3789887d22aSLv Zheng static void acpi_ec_submit_request(struct acpi_ec *ec)
3799887d22aSLv Zheng {
3809887d22aSLv Zheng 	ec->reference_count++;
3814446abc9SDaniel Drake 	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
382406857f7SDaniel Drake 	    ec->gpe >= 0 && ec->reference_count == 1)
3839887d22aSLv Zheng 		acpi_ec_enable_gpe(ec, true);
3849887d22aSLv Zheng }
3859887d22aSLv Zheng 
acpi_ec_complete_request(struct acpi_ec * ec)3869887d22aSLv Zheng static void acpi_ec_complete_request(struct acpi_ec *ec)
3879887d22aSLv Zheng {
3889887d22aSLv Zheng 	bool flushed = false;
3899887d22aSLv Zheng 
3909887d22aSLv Zheng 	ec->reference_count--;
3914446abc9SDaniel Drake 	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
392406857f7SDaniel Drake 	    ec->gpe >= 0 && ec->reference_count == 0)
3939887d22aSLv Zheng 		acpi_ec_disable_gpe(ec, true);
3949887d22aSLv Zheng 	flushed = acpi_ec_flushed(ec);
3959887d22aSLv Zheng 	if (flushed)
3969887d22aSLv Zheng 		wake_up(&ec->wait);
3979887d22aSLv Zheng }
3989887d22aSLv Zheng 
acpi_ec_mask_events(struct acpi_ec * ec)3994446abc9SDaniel Drake static void acpi_ec_mask_events(struct acpi_ec *ec)
400e1d4d90fSLv Zheng {
4014446abc9SDaniel Drake 	if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
402406857f7SDaniel Drake 		if (ec->gpe >= 0)
403e1d4d90fSLv Zheng 			acpi_ec_disable_gpe(ec, false);
404406857f7SDaniel Drake 		else
405406857f7SDaniel Drake 			disable_irq_nosync(ec->irq);
406406857f7SDaniel Drake 
4073535a3c1SLv Zheng 		ec_dbg_drv("Polling enabled");
4084446abc9SDaniel Drake 		set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
409e1d4d90fSLv Zheng 	}
410e1d4d90fSLv Zheng }
411e1d4d90fSLv Zheng 
acpi_ec_unmask_events(struct acpi_ec * ec)4124446abc9SDaniel Drake static void acpi_ec_unmask_events(struct acpi_ec *ec)
413e1d4d90fSLv Zheng {
4144446abc9SDaniel Drake 	if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
4154446abc9SDaniel Drake 		clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
416406857f7SDaniel Drake 		if (ec->gpe >= 0)
417e1d4d90fSLv Zheng 			acpi_ec_enable_gpe(ec, false);
418406857f7SDaniel Drake 		else
419406857f7SDaniel Drake 			enable_irq(ec->irq);
420406857f7SDaniel Drake 
4213535a3c1SLv Zheng 		ec_dbg_drv("Polling disabled");
422e1d4d90fSLv Zheng 	}
423e1d4d90fSLv Zheng }
424e1d4d90fSLv Zheng 
4259887d22aSLv Zheng /*
4269887d22aSLv Zheng  * acpi_ec_submit_flushable_request() - Increase the reference count unless
4279887d22aSLv Zheng  *                                      the flush operation is not in
4289887d22aSLv Zheng  *                                      progress
4299887d22aSLv Zheng  * @ec: the EC device
4309887d22aSLv Zheng  *
4319887d22aSLv Zheng  * This function must be used before taking a new action that should hold
4329887d22aSLv Zheng  * the reference count.  If this function returns false, then the action
4339887d22aSLv Zheng  * must be discarded or it will prevent the flush operation from being
4349887d22aSLv Zheng  * completed.
4359887d22aSLv Zheng  */
acpi_ec_submit_flushable_request(struct acpi_ec * ec)43637d11391SRafael J. Wysocki static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
4379887d22aSLv Zheng {
43837d11391SRafael J. Wysocki 	if (!acpi_ec_started(ec))
4399887d22aSLv Zheng 		return false;
4409887d22aSLv Zheng 	acpi_ec_submit_request(ec);
4419887d22aSLv Zheng 	return true;
4429887d22aSLv Zheng }
4439887d22aSLv Zheng 
acpi_ec_submit_event(struct acpi_ec * ec)4449aa60f3cSRafael J. Wysocki static void acpi_ec_submit_event(struct acpi_ec *ec)
44574443bbeSLv Zheng {
4469aa60f3cSRafael J. Wysocki 	/*
4479aa60f3cSRafael J. Wysocki 	 * It is safe to mask the events here, because acpi_ec_close_event()
4489aa60f3cSRafael J. Wysocki 	 * will run at least once after this.
4499aa60f3cSRafael J. Wysocki 	 */
4504446abc9SDaniel Drake 	acpi_ec_mask_events(ec);
4511ab69f27SLv Zheng 	if (!acpi_ec_event_enabled(ec))
4529aa60f3cSRafael J. Wysocki 		return;
453ca8283dcSRafael J. Wysocki 
45454b86141SRafael J. Wysocki 	if (ec->event_state != EC_EVENT_READY)
45554b86141SRafael J. Wysocki 		return;
45654b86141SRafael J. Wysocki 
4579d8993beSLv Zheng 	ec_dbg_evt("Command(%s) submitted/blocked",
4589d8993beSLv Zheng 		   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
459c33676aaSRafael J. Wysocki 
460c33676aaSRafael J. Wysocki 	ec->event_state = EC_EVENT_IN_PROGRESS;
461c793570dSRafael J. Wysocki 	/*
46254b86141SRafael J. Wysocki 	 * If events_to_process is greater than 0 at this point, the while ()
46354b86141SRafael J. Wysocki 	 * loop in acpi_ec_event_handler() is still running and incrementing
46454b86141SRafael J. Wysocki 	 * events_to_process will cause it to invoke acpi_ec_submit_query() once
46554b86141SRafael J. Wysocki 	 * more, so it is not necessary to queue up the event work to start the
46654b86141SRafael J. Wysocki 	 * same loop again.
467c793570dSRafael J. Wysocki 	 */
468c793570dSRafael J. Wysocki 	if (ec->events_to_process++ > 0)
4699aa60f3cSRafael J. Wysocki 		return;
470c793570dSRafael J. Wysocki 
4714a9af6caSRafael J. Wysocki 	ec->events_in_progress++;
4729aa60f3cSRafael J. Wysocki 	queue_work(ec_wq, &ec->work);
473f252cb09SLv Zheng }
474f252cb09SLv Zheng 
acpi_ec_complete_event(struct acpi_ec * ec)475c33676aaSRafael J. Wysocki static void acpi_ec_complete_event(struct acpi_ec *ec)
476c33676aaSRafael J. Wysocki {
477c33676aaSRafael J. Wysocki 	if (ec->event_state == EC_EVENT_IN_PROGRESS)
478c33676aaSRafael J. Wysocki 		ec->event_state = EC_EVENT_COMPLETE;
479c33676aaSRafael J. Wysocki }
480c33676aaSRafael J. Wysocki 
acpi_ec_close_event(struct acpi_ec * ec)481eafe7509SRafael J. Wysocki static void acpi_ec_close_event(struct acpi_ec *ec)
482f252cb09SLv Zheng {
483c33676aaSRafael J. Wysocki 	if (ec->event_state != EC_EVENT_READY)
4849d8993beSLv Zheng 		ec_dbg_evt("Command(%s) unblocked",
4859d8993beSLv Zheng 			   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
486c33676aaSRafael J. Wysocki 
487c33676aaSRafael J. Wysocki 	ec->event_state = EC_EVENT_READY;
4884446abc9SDaniel Drake 	acpi_ec_unmask_events(ec);
48974443bbeSLv Zheng }
49074443bbeSLv Zheng 
__acpi_ec_enable_event(struct acpi_ec * ec)491750f628bSLv Zheng static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
492750f628bSLv Zheng {
493750f628bSLv Zheng 	if (!test_and_set_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
494750f628bSLv Zheng 		ec_log_drv("event unblocked");
49553c5eaabSLv Zheng 	/*
49653c5eaabSLv Zheng 	 * Unconditionally invoke this once after enabling the event
49753c5eaabSLv Zheng 	 * handling mechanism to detect the pending events.
49853c5eaabSLv Zheng 	 */
4992e84ea5aSSebastian Andrzej Siewior 	advance_transaction(ec, false);
500750f628bSLv Zheng }
501750f628bSLv Zheng 
__acpi_ec_disable_event(struct acpi_ec * ec)502750f628bSLv Zheng static inline void __acpi_ec_disable_event(struct acpi_ec *ec)
503750f628bSLv Zheng {
504750f628bSLv Zheng 	if (test_and_clear_bit(EC_FLAGS_QUERY_ENABLED, &ec->flags))
505750f628bSLv Zheng 		ec_log_drv("event blocked");
506750f628bSLv Zheng }
507750f628bSLv Zheng 
508b6a3e147SZhang Rui /*
509b6a3e147SZhang Rui  * Process _Q events that might have accumulated in the EC.
510b6a3e147SZhang Rui  * Run with locked ec mutex.
511b6a3e147SZhang Rui  */
acpi_ec_clear(struct acpi_ec * ec)512b6a3e147SZhang Rui static void acpi_ec_clear(struct acpi_ec *ec)
513b6a3e147SZhang Rui {
5141f235044SRafael J. Wysocki 	int i;
515b6a3e147SZhang Rui 
516b6a3e147SZhang Rui 	for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
517eafe7509SRafael J. Wysocki 		if (acpi_ec_submit_query(ec))
518b6a3e147SZhang Rui 			break;
519b6a3e147SZhang Rui 	}
520b6a3e147SZhang Rui 	if (unlikely(i == ACPI_EC_CLEAR_MAX))
521b6a3e147SZhang Rui 		pr_warn("Warning: Maximum of %d stale EC events cleared\n", i);
522b6a3e147SZhang Rui 	else
523b6a3e147SZhang Rui 		pr_info("%d stale EC events cleared\n", i);
524b6a3e147SZhang Rui }
525b6a3e147SZhang Rui 
acpi_ec_enable_event(struct acpi_ec * ec)526750f628bSLv Zheng static void acpi_ec_enable_event(struct acpi_ec *ec)
527750f628bSLv Zheng {
528750f628bSLv Zheng 	unsigned long flags;
529750f628bSLv Zheng 
530750f628bSLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
531750f628bSLv Zheng 	if (acpi_ec_started(ec))
532750f628bSLv Zheng 		__acpi_ec_enable_event(ec);
533750f628bSLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
534b6a3e147SZhang Rui 
535b6a3e147SZhang Rui 	/* Drain additional events if hardware requires that */
536b6a3e147SZhang Rui 	if (EC_FLAGS_CLEAR_ON_RESUME)
537b6a3e147SZhang Rui 		acpi_ec_clear(ec);
538750f628bSLv Zheng }
539750f628bSLv Zheng 
540eab05ec3SEric Biggers #ifdef CONFIG_PM_SLEEP
__acpi_ec_flush_work(void)541016b87caSRafael J. Wysocki static void __acpi_ec_flush_work(void)
54239a2a2aaSLv Zheng {
5434a9af6caSRafael J. Wysocki 	flush_workqueue(ec_wq); /* flush ec->work */
544016b87caSRafael J. Wysocki 	flush_workqueue(ec_query_wq); /* flush queries */
54539a2a2aaSLv Zheng }
54639a2a2aaSLv Zheng 
acpi_ec_disable_event(struct acpi_ec * ec)54739a2a2aaSLv Zheng static void acpi_ec_disable_event(struct acpi_ec *ec)
54839a2a2aaSLv Zheng {
54939a2a2aaSLv Zheng 	unsigned long flags;
55039a2a2aaSLv Zheng 
55139a2a2aaSLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
55239a2a2aaSLv Zheng 	__acpi_ec_disable_event(ec);
55339a2a2aaSLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
554016b87caSRafael J. Wysocki 
555016b87caSRafael J. Wysocki 	/*
556016b87caSRafael J. Wysocki 	 * When ec_freeze_events is true, we need to flush events in
557016b87caSRafael J. Wysocki 	 * the proper position before entering the noirq stage.
558016b87caSRafael J. Wysocki 	 */
559016b87caSRafael J. Wysocki 	__acpi_ec_flush_work();
56039a2a2aaSLv Zheng }
561880a6627SRafael J. Wysocki 
acpi_ec_flush_work(void)562880a6627SRafael J. Wysocki void acpi_ec_flush_work(void)
563880a6627SRafael J. Wysocki {
564f0ac20c3SRafael J. Wysocki 	/* Without ec_wq there is nothing to flush. */
565f0ac20c3SRafael J. Wysocki 	if (!ec_wq)
566016b87caSRafael J. Wysocki 		return;
567880a6627SRafael J. Wysocki 
568016b87caSRafael J. Wysocki 	__acpi_ec_flush_work();
569880a6627SRafael J. Wysocki }
570eab05ec3SEric Biggers #endif /* CONFIG_PM_SLEEP */
57139a2a2aaSLv Zheng 
acpi_ec_guard_event(struct acpi_ec * ec)5721d68d261SLv Zheng static bool acpi_ec_guard_event(struct acpi_ec *ec)
5731d68d261SLv Zheng {
57461197547SLv Zheng 	unsigned long flags;
575c33676aaSRafael J. Wysocki 	bool guarded;
57661197547SLv Zheng 
57761197547SLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
57861197547SLv Zheng 	/*
57961197547SLv Zheng 	 * If firmware SCI_EVT clearing timing is "event", we actually
58061197547SLv Zheng 	 * don't know when the SCI_EVT will be cleared by firmware after
58161197547SLv Zheng 	 * evaluating _Qxx, so we need to re-check SCI_EVT after waiting an
58261197547SLv Zheng 	 * acceptable period.
58361197547SLv Zheng 	 *
584c33676aaSRafael J. Wysocki 	 * The guarding period is applicable if the event state is not
585c33676aaSRafael J. Wysocki 	 * EC_EVENT_READY, but otherwise if the current transaction is of the
586c33676aaSRafael J. Wysocki 	 * ACPI_EC_COMMAND_QUERY type, the guarding should have elapsed already
587c33676aaSRafael J. Wysocki 	 * and it should not be applied to let the transaction transition into
588c33676aaSRafael J. Wysocki 	 * the ACPI_EC_COMMAND_POLL state immediately.
58961197547SLv Zheng 	 */
590c33676aaSRafael J. Wysocki 	guarded = ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
591c33676aaSRafael J. Wysocki 		ec->event_state != EC_EVENT_READY &&
592c33676aaSRafael J. Wysocki 		(!ec->curr || ec->curr->command != ACPI_EC_COMMAND_QUERY);
59361197547SLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
59461197547SLv Zheng 	return guarded;
5951d68d261SLv Zheng }
5961d68d261SLv Zheng 
ec_transaction_polled(struct acpi_ec * ec)597d8d031a6SLv Zheng static int ec_transaction_polled(struct acpi_ec *ec)
598d8d031a6SLv Zheng {
599d8d031a6SLv Zheng 	unsigned long flags;
600d8d031a6SLv Zheng 	int ret = 0;
601d8d031a6SLv Zheng 
602d8d031a6SLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
603d8d031a6SLv Zheng 	if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
604d8d031a6SLv Zheng 		ret = 1;
605d8d031a6SLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
606d8d031a6SLv Zheng 	return ret;
607d8d031a6SLv Zheng }
608d8d031a6SLv Zheng 
ec_transaction_completed(struct acpi_ec * ec)609f92fca00SLv Zheng static int ec_transaction_completed(struct acpi_ec *ec)
6106ffb221aSDenis M. Sadykov {
6117c6db4e0SAlexey Starikovskiy 	unsigned long flags;
6127c6db4e0SAlexey Starikovskiy 	int ret = 0;
6137a73e60eSLv Zheng 
614f351d027SFeng Tang 	spin_lock_irqsave(&ec->lock, flags);
615c0d65341SLv Zheng 	if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_COMPLETE))
6167c6db4e0SAlexey Starikovskiy 		ret = 1;
617f351d027SFeng Tang 	spin_unlock_irqrestore(&ec->lock, flags);
6187c6db4e0SAlexey Starikovskiy 	return ret;
61945bea155SLuming Yu }
62045bea155SLuming Yu 
ec_transaction_transition(struct acpi_ec * ec,unsigned long flag)621f8b8eb71SLv Zheng static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag)
622f8b8eb71SLv Zheng {
623f8b8eb71SLv Zheng 	ec->curr->flags |= flag;
624c33676aaSRafael J. Wysocki 
625c33676aaSRafael J. Wysocki 	if (ec->curr->command != ACPI_EC_COMMAND_QUERY)
626c33676aaSRafael J. Wysocki 		return;
627c33676aaSRafael J. Wysocki 
628c33676aaSRafael J. Wysocki 	switch (ec_event_clearing) {
629c33676aaSRafael J. Wysocki 	case ACPI_EC_EVT_TIMING_STATUS:
630c33676aaSRafael J. Wysocki 		if (flag == ACPI_EC_COMMAND_POLL)
631eafe7509SRafael J. Wysocki 			acpi_ec_close_event(ec);
632c33676aaSRafael J. Wysocki 
633c33676aaSRafael J. Wysocki 		return;
634c33676aaSRafael J. Wysocki 
635c33676aaSRafael J. Wysocki 	case ACPI_EC_EVT_TIMING_QUERY:
636c33676aaSRafael J. Wysocki 		if (flag == ACPI_EC_COMMAND_COMPLETE)
637eafe7509SRafael J. Wysocki 			acpi_ec_close_event(ec);
638c33676aaSRafael J. Wysocki 
639c33676aaSRafael J. Wysocki 		return;
640c33676aaSRafael J. Wysocki 
641c33676aaSRafael J. Wysocki 	case ACPI_EC_EVT_TIMING_EVENT:
642c33676aaSRafael J. Wysocki 		if (flag == ACPI_EC_COMMAND_COMPLETE)
643c33676aaSRafael J. Wysocki 			acpi_ec_complete_event(ec);
644f8b8eb71SLv Zheng 	}
645f8b8eb71SLv Zheng }
646f8b8eb71SLv Zheng 
acpi_ec_spurious_interrupt(struct acpi_ec * ec,struct transaction * t)647631734fcSRafael J. Wysocki static void acpi_ec_spurious_interrupt(struct acpi_ec *ec, struct transaction *t)
648631734fcSRafael J. Wysocki {
649631734fcSRafael J. Wysocki 	if (t->irq_count < ec_storm_threshold)
650631734fcSRafael J. Wysocki 		++t->irq_count;
651631734fcSRafael J. Wysocki 
652631734fcSRafael J. Wysocki 	/* Trigger if the threshold is 0 too. */
653631734fcSRafael J. Wysocki 	if (t->irq_count == ec_storm_threshold)
654631734fcSRafael J. Wysocki 		acpi_ec_mask_events(ec);
655631734fcSRafael J. Wysocki }
656631734fcSRafael J. Wysocki 
advance_transaction(struct acpi_ec * ec,bool interrupt)6579aa60f3cSRafael J. Wysocki static void advance_transaction(struct acpi_ec *ec, bool interrupt)
6587c6db4e0SAlexey Starikovskiy {
659902675faSRafael J. Wysocki 	struct transaction *t = ec->curr;
660c0d65341SLv Zheng 	bool wakeup = false;
661902675faSRafael J. Wysocki 	u8 status;
662b76b51baSFeng Tang 
6632e84ea5aSSebastian Andrzej Siewior 	ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
664d269fb03SRafael J. Wysocki 
66566b42b78SLv Zheng 	status = acpi_ec_read_status(ec);
666902675faSRafael J. Wysocki 
6671d68d261SLv Zheng 	/*
6681d68d261SLv Zheng 	 * Another IRQ or a guarded polling mode advancement is detected,
6691d68d261SLv Zheng 	 * the next QR_EC submission is then allowed.
6701d68d261SLv Zheng 	 */
6711d68d261SLv Zheng 	if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
6721d68d261SLv Zheng 		if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
673c33676aaSRafael J. Wysocki 		    ec->event_state == EC_EVENT_COMPLETE)
674eafe7509SRafael J. Wysocki 			acpi_ec_close_event(ec);
675c33676aaSRafael J. Wysocki 
676b76b51baSFeng Tang 		if (!t)
677902675faSRafael J. Wysocki 			goto out;
678902675faSRafael J. Wysocki 	}
679902675faSRafael J. Wysocki 
680f92fca00SLv Zheng 	if (t->flags & ACPI_EC_COMMAND_POLL) {
681b76b51baSFeng Tang 		if (t->wlen > t->wi) {
6822a39a30fSRafael J. Wysocki 			if (!(status & ACPI_EC_FLAG_IBF))
683f92fca00SLv Zheng 				acpi_ec_write_data(ec, t->wdata[t->wi++]);
684631734fcSRafael J. Wysocki 			else if (interrupt && !(status & ACPI_EC_FLAG_SCI))
685631734fcSRafael J. Wysocki 				acpi_ec_spurious_interrupt(ec, t);
686b76b51baSFeng Tang 		} else if (t->rlen > t->ri) {
6872a39a30fSRafael J. Wysocki 			if (status & ACPI_EC_FLAG_OBF) {
688b76b51baSFeng Tang 				t->rdata[t->ri++] = acpi_ec_read_data(ec);
689c0d65341SLv Zheng 				if (t->rlen == t->ri) {
690f8b8eb71SLv Zheng 					ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
6912a39a30fSRafael J. Wysocki 					wakeup = true;
6923afcf2ecSLv Zheng 					if (t->command == ACPI_EC_COMMAND_QUERY)
6939d8993beSLv Zheng 						ec_dbg_evt("Command(%s) completed by hardware",
6949d8993beSLv Zheng 							   acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
695c0d65341SLv Zheng 				}
696631734fcSRafael J. Wysocki 			} else if (interrupt && !(status & ACPI_EC_FLAG_SCI)) {
697631734fcSRafael J. Wysocki 				acpi_ec_spurious_interrupt(ec, t);
698631734fcSRafael J. Wysocki 			}
6992a39a30fSRafael J. Wysocki 		} else if (t->wlen == t->wi && !(status & ACPI_EC_FLAG_IBF)) {
700f8b8eb71SLv Zheng 			ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
701c0d65341SLv Zheng 			wakeup = true;
702c0d65341SLv Zheng 		}
703b1e14999SRafael J. Wysocki 	} else if (!(status & ACPI_EC_FLAG_IBF)) {
704f92fca00SLv Zheng 		acpi_ec_write_cmd(ec, t->command);
705f8b8eb71SLv Zheng 		ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
706f92fca00SLv Zheng 	}
707902675faSRafael J. Wysocki 
7080c78808fSLv Zheng out:
70974443bbeSLv Zheng 	if (status & ACPI_EC_FLAG_SCI)
7109aa60f3cSRafael J. Wysocki 		acpi_ec_submit_event(ec);
7112a39a30fSRafael J. Wysocki 
7122e84ea5aSSebastian Andrzej Siewior 	if (wakeup && interrupt)
7130c78808fSLv Zheng 		wake_up(&ec->wait);
714f92fca00SLv Zheng }
715a3cd8d27SFeng Tang 
start_transaction(struct acpi_ec * ec)716f92fca00SLv Zheng static void start_transaction(struct acpi_ec *ec)
717f92fca00SLv Zheng {
718f92fca00SLv Zheng 	ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
719f92fca00SLv Zheng 	ec->curr->flags = 0;
720d8d031a6SLv Zheng }
721d8d031a6SLv Zheng 
ec_guard(struct acpi_ec * ec)722d8d031a6SLv Zheng static int ec_guard(struct acpi_ec *ec)
723d8d031a6SLv Zheng {
724c3a696b6SLv Zheng 	unsigned long guard = usecs_to_jiffies(ec->polling_guard);
725d8d031a6SLv Zheng 	unsigned long timeout = ec->timestamp + guard;
726d8d031a6SLv Zheng 
72761197547SLv Zheng 	/* Ensure guarding period before polling EC status */
728d8d031a6SLv Zheng 	do {
729c3a696b6SLv Zheng 		if (ec->busy_polling) {
730d8d031a6SLv Zheng 			/* Perform busy polling */
731d8d031a6SLv Zheng 			if (ec_transaction_completed(ec))
732d8d031a6SLv Zheng 				return 0;
733d8d031a6SLv Zheng 			udelay(jiffies_to_usecs(guard));
734d8d031a6SLv Zheng 		} else {
735d8d031a6SLv Zheng 			/*
736d8d031a6SLv Zheng 			 * Perform wait polling
73761197547SLv Zheng 			 * 1. Wait the transaction to be completed by the
73861197547SLv Zheng 			 *    GPE handler after the transaction enters
73961197547SLv Zheng 			 *    ACPI_EC_COMMAND_POLL state.
74061197547SLv Zheng 			 * 2. A special guarding logic is also required
74161197547SLv Zheng 			 *    for event clearing mode "event" before the
74261197547SLv Zheng 			 *    transaction enters ACPI_EC_COMMAND_POLL
74361197547SLv Zheng 			 *    state.
744d8d031a6SLv Zheng 			 */
7451d68d261SLv Zheng 			if (!ec_transaction_polled(ec) &&
7461d68d261SLv Zheng 			    !acpi_ec_guard_event(ec))
747d8d031a6SLv Zheng 				break;
748d8d031a6SLv Zheng 			if (wait_event_timeout(ec->wait,
749d8d031a6SLv Zheng 					       ec_transaction_completed(ec),
750d8d031a6SLv Zheng 					       guard))
751d8d031a6SLv Zheng 				return 0;
752d8d031a6SLv Zheng 		}
753d8d031a6SLv Zheng 	} while (time_before(jiffies, timeout));
754d8d031a6SLv Zheng 	return -ETIME;
75545bea155SLuming Yu }
756451566f4SDmitry Torokhov 
ec_poll(struct acpi_ec * ec)7577c6db4e0SAlexey Starikovskiy static int ec_poll(struct acpi_ec *ec)
7587c6db4e0SAlexey Starikovskiy {
7592a84cb98SAlexey Starikovskiy 	unsigned long flags;
76028fe5c82SLan Tianyu 	int repeat = 5; /* number of command restarts */
7617a73e60eSLv Zheng 
7622a84cb98SAlexey Starikovskiy 	while (repeat--) {
7632a84cb98SAlexey Starikovskiy 		unsigned long delay = jiffies +
7647a18e96dSThomas Renninger 			msecs_to_jiffies(ec_delay);
7652a84cb98SAlexey Starikovskiy 		do {
766d8d031a6SLv Zheng 			if (!ec_guard(ec))
7679d699ed9SZhao Yakui 				return 0;
768f92fca00SLv Zheng 			spin_lock_irqsave(&ec->lock, flags);
7692e84ea5aSSebastian Andrzej Siewior 			advance_transaction(ec, false);
770f92fca00SLv Zheng 			spin_unlock_irqrestore(&ec->lock, flags);
7712a84cb98SAlexey Starikovskiy 		} while (time_before(jiffies, delay));
77216a26e85SLan Tianyu 		pr_debug("controller reset, restart transaction\n");
773f351d027SFeng Tang 		spin_lock_irqsave(&ec->lock, flags);
7742a84cb98SAlexey Starikovskiy 		start_transaction(ec);
775f351d027SFeng Tang 		spin_unlock_irqrestore(&ec->lock, flags);
776080e412cSAlexey Starikovskiy 	}
777b77d81b2SAlexey Starikovskiy 	return -ETIME;
7781da177e4SLinus Torvalds }
7791da177e4SLinus Torvalds 
acpi_ec_transaction_unlocked(struct acpi_ec * ec,struct transaction * t)7808463200aSAlexey Starikovskiy static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
7812a84cb98SAlexey Starikovskiy 					struct transaction *t)
78245bea155SLuming Yu {
7837c6db4e0SAlexey Starikovskiy 	unsigned long tmp;
7847c6db4e0SAlexey Starikovskiy 	int ret = 0;
7857a73e60eSLv Zheng 
786*93d065b7SRafael J. Wysocki 	if (t->rdata)
787*93d065b7SRafael J. Wysocki 		memset(t->rdata, 0, t->rlen);
788*93d065b7SRafael J. Wysocki 
7897c6db4e0SAlexey Starikovskiy 	/* start transaction */
790f351d027SFeng Tang 	spin_lock_irqsave(&ec->lock, tmp);
7919887d22aSLv Zheng 	/* Enable GPE for command processing (IBF=0/OBF=1) */
79237d11391SRafael J. Wysocki 	if (!acpi_ec_submit_flushable_request(ec)) {
793ad479e7fSLv Zheng 		ret = -EINVAL;
794ad479e7fSLv Zheng 		goto unlock;
795ad479e7fSLv Zheng 	}
796770970f0SLv Zheng 	ec_dbg_ref(ec, "Increase command");
7977c6db4e0SAlexey Starikovskiy 	/* following two actions should be kept atomic */
7988463200aSAlexey Starikovskiy 	ec->curr = t;
7993535a3c1SLv Zheng 	ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
800a2f93aeaSAlexey Starikovskiy 	start_transaction(ec);
801df9ff918SLv Zheng 	spin_unlock_irqrestore(&ec->lock, tmp);
802d8d031a6SLv Zheng 
803df9ff918SLv Zheng 	ret = ec_poll(ec);
804d8d031a6SLv Zheng 
805df9ff918SLv Zheng 	spin_lock_irqsave(&ec->lock, tmp);
806e1d4d90fSLv Zheng 	if (t->irq_count == ec_storm_threshold)
8074446abc9SDaniel Drake 		acpi_ec_unmask_events(ec);
8083535a3c1SLv Zheng 	ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
8098463200aSAlexey Starikovskiy 	ec->curr = NULL;
8109887d22aSLv Zheng 	/* Disable GPE for command processing (IBF=0/OBF=1) */
8119887d22aSLv Zheng 	acpi_ec_complete_request(ec);
812770970f0SLv Zheng 	ec_dbg_ref(ec, "Decrease command");
813ad479e7fSLv Zheng unlock:
814f351d027SFeng Tang 	spin_unlock_irqrestore(&ec->lock, tmp);
8157c6db4e0SAlexey Starikovskiy 	return ret;
816d7a76e4cSLennart Poettering }
817d7a76e4cSLennart Poettering 
acpi_ec_transaction(struct acpi_ec * ec,struct transaction * t)8182a84cb98SAlexey Starikovskiy static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
8191da177e4SLinus Torvalds {
820d7a76e4cSLennart Poettering 	int status;
821451566f4SDmitry Torokhov 	u32 glk;
8227a73e60eSLv Zheng 
8238463200aSAlexey Starikovskiy 	if (!ec || (!t) || (t->wlen && !t->wdata) || (t->rlen && !t->rdata))
824d550d98dSPatrick Mochel 		return -EINVAL;
825d8d031a6SLv Zheng 
826f351d027SFeng Tang 	mutex_lock(&ec->mutex);
827703959d4SDenis M. Sadykov 	if (ec->global_lock) {
8281da177e4SLinus Torvalds 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
829c24e912bSAlexey Starikovskiy 		if (ACPI_FAILURE(status)) {
8307c6db4e0SAlexey Starikovskiy 			status = -ENODEV;
8317c6db4e0SAlexey Starikovskiy 			goto unlock;
8321da177e4SLinus Torvalds 		}
833c24e912bSAlexey Starikovskiy 	}
834a62e8f19SAlexey Starikovskiy 
8352a84cb98SAlexey Starikovskiy 	status = acpi_ec_transaction_unlocked(ec, t);
836a62e8f19SAlexey Starikovskiy 
837703959d4SDenis M. Sadykov 	if (ec->global_lock)
8381da177e4SLinus Torvalds 		acpi_release_global_lock(glk);
8397c6db4e0SAlexey Starikovskiy unlock:
840f351d027SFeng Tang 	mutex_unlock(&ec->mutex);
841d550d98dSPatrick Mochel 	return status;
8421da177e4SLinus Torvalds }
8431da177e4SLinus Torvalds 
acpi_ec_burst_enable(struct acpi_ec * ec)8448a383ef0SRoel Kluin static int acpi_ec_burst_enable(struct acpi_ec *ec)
845c45aac43SAlexey Starikovskiy {
846c45aac43SAlexey Starikovskiy 	u8 d;
8478463200aSAlexey Starikovskiy 	struct transaction t = {.command = ACPI_EC_BURST_ENABLE,
8488463200aSAlexey Starikovskiy 				.wdata = NULL, .rdata = &d,
8498463200aSAlexey Starikovskiy 				.wlen = 0, .rlen = 1};
8508463200aSAlexey Starikovskiy 
851*93d065b7SRafael J. Wysocki 	return acpi_ec_transaction_unlocked(ec, &t);
852c45aac43SAlexey Starikovskiy }
853c45aac43SAlexey Starikovskiy 
acpi_ec_burst_disable(struct acpi_ec * ec)8548a383ef0SRoel Kluin static int acpi_ec_burst_disable(struct acpi_ec *ec)
855c45aac43SAlexey Starikovskiy {
8568463200aSAlexey Starikovskiy 	struct transaction t = {.command = ACPI_EC_BURST_DISABLE,
8578463200aSAlexey Starikovskiy 				.wdata = NULL, .rdata = NULL,
8588463200aSAlexey Starikovskiy 				.wlen = 0, .rlen = 0};
8598463200aSAlexey Starikovskiy 
8607c6db4e0SAlexey Starikovskiy 	return (acpi_ec_read_status(ec) & ACPI_EC_FLAG_BURST) ?
861*93d065b7SRafael J. Wysocki 				acpi_ec_transaction_unlocked(ec, &t) : 0;
862c45aac43SAlexey Starikovskiy }
863c45aac43SAlexey Starikovskiy 
acpi_ec_read(struct acpi_ec * ec,u8 address,u8 * data)8646ffb221aSDenis M. Sadykov static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
8653576cf61SDenis M. Sadykov {
8663576cf61SDenis M. Sadykov 	int result;
8673576cf61SDenis M. Sadykov 	u8 d;
8688463200aSAlexey Starikovskiy 	struct transaction t = {.command = ACPI_EC_COMMAND_READ,
8698463200aSAlexey Starikovskiy 				.wdata = &address, .rdata = &d,
8708463200aSAlexey Starikovskiy 				.wlen = 1, .rlen = 1};
8713576cf61SDenis M. Sadykov 
8722a84cb98SAlexey Starikovskiy 	result = acpi_ec_transaction(ec, &t);
8733576cf61SDenis M. Sadykov 	*data = d;
8743576cf61SDenis M. Sadykov 	return result;
8753576cf61SDenis M. Sadykov }
8766ffb221aSDenis M. Sadykov 
acpi_ec_read_unlocked(struct acpi_ec * ec,u8 address,u8 * data)877*93d065b7SRafael J. Wysocki static int acpi_ec_read_unlocked(struct acpi_ec *ec, u8 address, u8 *data)
878*93d065b7SRafael J. Wysocki {
879*93d065b7SRafael J. Wysocki 	int result;
880*93d065b7SRafael J. Wysocki 	u8 d;
881*93d065b7SRafael J. Wysocki 	struct transaction t = {.command = ACPI_EC_COMMAND_READ,
882*93d065b7SRafael J. Wysocki 				.wdata = &address, .rdata = &d,
883*93d065b7SRafael J. Wysocki 				.wlen = 1, .rlen = 1};
884*93d065b7SRafael J. Wysocki 
885*93d065b7SRafael J. Wysocki 	result = acpi_ec_transaction_unlocked(ec, &t);
886*93d065b7SRafael J. Wysocki 	*data = d;
887*93d065b7SRafael J. Wysocki 	return result;
888*93d065b7SRafael J. Wysocki }
889*93d065b7SRafael J. Wysocki 
acpi_ec_write(struct acpi_ec * ec,u8 address,u8 data)8903576cf61SDenis M. Sadykov static int acpi_ec_write(struct acpi_ec *ec, u8 address, u8 data)
8913576cf61SDenis M. Sadykov {
8923576cf61SDenis M. Sadykov 	u8 wdata[2] = { address, data };
8938463200aSAlexey Starikovskiy 	struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
8948463200aSAlexey Starikovskiy 				.wdata = wdata, .rdata = NULL,
8958463200aSAlexey Starikovskiy 				.wlen = 2, .rlen = 0};
8968463200aSAlexey Starikovskiy 
8972a84cb98SAlexey Starikovskiy 	return acpi_ec_transaction(ec, &t);
8983576cf61SDenis M. Sadykov }
8993576cf61SDenis M. Sadykov 
acpi_ec_write_unlocked(struct acpi_ec * ec,u8 address,u8 data)900*93d065b7SRafael J. Wysocki static int acpi_ec_write_unlocked(struct acpi_ec *ec, u8 address, u8 data)
901*93d065b7SRafael J. Wysocki {
902*93d065b7SRafael J. Wysocki 	u8 wdata[2] = { address, data };
903*93d065b7SRafael J. Wysocki 	struct transaction t = {.command = ACPI_EC_COMMAND_WRITE,
904*93d065b7SRafael J. Wysocki 				.wdata = wdata, .rdata = NULL,
905*93d065b7SRafael J. Wysocki 				.wlen = 2, .rlen = 0};
906*93d065b7SRafael J. Wysocki 
907*93d065b7SRafael J. Wysocki 	return acpi_ec_transaction_unlocked(ec, &t);
908*93d065b7SRafael J. Wysocki }
909*93d065b7SRafael J. Wysocki 
ec_read(u8 addr,u8 * val)91050526df6SLen Brown int ec_read(u8 addr, u8 *val)
9111da177e4SLinus Torvalds {
9121da177e4SLinus Torvalds 	int err;
9136ffb221aSDenis M. Sadykov 	u8 temp_data;
9141da177e4SLinus Torvalds 
9151da177e4SLinus Torvalds 	if (!first_ec)
9161da177e4SLinus Torvalds 		return -ENODEV;
9171da177e4SLinus Torvalds 
918d033879cSAlexey Starikovskiy 	err = acpi_ec_read(first_ec, addr, &temp_data);
9191da177e4SLinus Torvalds 
9201da177e4SLinus Torvalds 	if (!err) {
9211da177e4SLinus Torvalds 		*val = temp_data;
9221da177e4SLinus Torvalds 		return 0;
9237a73e60eSLv Zheng 	}
9241da177e4SLinus Torvalds 	return err;
9251da177e4SLinus Torvalds }
9261da177e4SLinus Torvalds EXPORT_SYMBOL(ec_read);
9271da177e4SLinus Torvalds 
ec_write(u8 addr,u8 val)92850526df6SLen Brown int ec_write(u8 addr, u8 val)
9291da177e4SLinus Torvalds {
9301da177e4SLinus Torvalds 	if (!first_ec)
9311da177e4SLinus Torvalds 		return -ENODEV;
9321da177e4SLinus Torvalds 
933b3c0e38bSye xingchen 	return acpi_ec_write(first_ec, addr, val);
9341da177e4SLinus Torvalds }
9351da177e4SLinus Torvalds EXPORT_SYMBOL(ec_write);
9361da177e4SLinus Torvalds 
ec_transaction(u8 command,const u8 * wdata,unsigned wdata_len,u8 * rdata,unsigned rdata_len)937616362deSRandy Dunlap int ec_transaction(u8 command,
938d7a76e4cSLennart Poettering 		   const u8 *wdata, unsigned wdata_len,
9391cb7b1e0SThomas Renninger 		   u8 *rdata, unsigned rdata_len)
94045bea155SLuming Yu {
9418463200aSAlexey Starikovskiy 	struct transaction t = {.command = command,
9428463200aSAlexey Starikovskiy 				.wdata = wdata, .rdata = rdata,
9438463200aSAlexey Starikovskiy 				.wlen = wdata_len, .rlen = rdata_len};
9447a73e60eSLv Zheng 
945d7a76e4cSLennart Poettering 	if (!first_ec)
946d7a76e4cSLennart Poettering 		return -ENODEV;
947d7a76e4cSLennart Poettering 
9482a84cb98SAlexey Starikovskiy 	return acpi_ec_transaction(first_ec, &t);
949d7a76e4cSLennart Poettering }
950ab9e43c6SLennart Poettering EXPORT_SYMBOL(ec_transaction);
951ab9e43c6SLennart Poettering 
9523e2abc5aSSeth Forshee /* Get the handle to the EC device */
ec_get_handle(void)9533e2abc5aSSeth Forshee acpi_handle ec_get_handle(void)
9543e2abc5aSSeth Forshee {
9553e2abc5aSSeth Forshee 	if (!first_ec)
9563e2abc5aSSeth Forshee 		return NULL;
9573e2abc5aSSeth Forshee 	return first_ec->handle;
9583e2abc5aSSeth Forshee }
9593e2abc5aSSeth Forshee EXPORT_SYMBOL(ec_get_handle);
9603e2abc5aSSeth Forshee 
acpi_ec_start(struct acpi_ec * ec,bool resuming)961ad479e7fSLv Zheng static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
962ad479e7fSLv Zheng {
963ad479e7fSLv Zheng 	unsigned long flags;
964ad479e7fSLv Zheng 
965ad479e7fSLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
966ad479e7fSLv Zheng 	if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
9673535a3c1SLv Zheng 		ec_dbg_drv("Starting EC");
9689887d22aSLv Zheng 		/* Enable GPE for event processing (SCI_EVT=1) */
969770970f0SLv Zheng 		if (!resuming) {
9709887d22aSLv Zheng 			acpi_ec_submit_request(ec);
971770970f0SLv Zheng 			ec_dbg_ref(ec, "Increase driver");
972c2b46d67SLv Zheng 		}
9733535a3c1SLv Zheng 		ec_log_drv("EC started");
974ad479e7fSLv Zheng 	}
975ad479e7fSLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
976ad479e7fSLv Zheng }
977ad479e7fSLv Zheng 
acpi_ec_stopped(struct acpi_ec * ec)9789887d22aSLv Zheng static bool acpi_ec_stopped(struct acpi_ec *ec)
9799887d22aSLv Zheng {
9809887d22aSLv Zheng 	unsigned long flags;
9819887d22aSLv Zheng 	bool flushed;
9829887d22aSLv Zheng 
9839887d22aSLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
9849887d22aSLv Zheng 	flushed = acpi_ec_flushed(ec);
9859887d22aSLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
9869887d22aSLv Zheng 	return flushed;
9879887d22aSLv Zheng }
9889887d22aSLv Zheng 
acpi_ec_stop(struct acpi_ec * ec,bool suspending)989ad479e7fSLv Zheng static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
990ad479e7fSLv Zheng {
991ad479e7fSLv Zheng 	unsigned long flags;
992ad479e7fSLv Zheng 
993ad479e7fSLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
994ad479e7fSLv Zheng 	if (acpi_ec_started(ec)) {
9953535a3c1SLv Zheng 		ec_dbg_drv("Stopping EC");
996ad479e7fSLv Zheng 		set_bit(EC_FLAGS_STOPPED, &ec->flags);
9979887d22aSLv Zheng 		spin_unlock_irqrestore(&ec->lock, flags);
9989887d22aSLv Zheng 		wait_event(ec->wait, acpi_ec_stopped(ec));
9999887d22aSLv Zheng 		spin_lock_irqsave(&ec->lock, flags);
10009887d22aSLv Zheng 		/* Disable GPE for event processing (SCI_EVT=1) */
1001770970f0SLv Zheng 		if (!suspending) {
10029887d22aSLv Zheng 			acpi_ec_complete_request(ec);
1003770970f0SLv Zheng 			ec_dbg_ref(ec, "Decrease driver");
100439a2a2aaSLv Zheng 		} else if (!ec_freeze_events)
1005750f628bSLv Zheng 			__acpi_ec_disable_event(ec);
1006ad479e7fSLv Zheng 		clear_bit(EC_FLAGS_STARTED, &ec->flags);
1007ad479e7fSLv Zheng 		clear_bit(EC_FLAGS_STOPPED, &ec->flags);
10083535a3c1SLv Zheng 		ec_log_drv("EC stopped");
1009ad479e7fSLv Zheng 	}
1010ad479e7fSLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
1011ad479e7fSLv Zheng }
1012ad479e7fSLv Zheng 
acpi_ec_enter_noirq(struct acpi_ec * ec)1013c3a696b6SLv Zheng static void acpi_ec_enter_noirq(struct acpi_ec *ec)
1014c3a696b6SLv Zheng {
1015c3a696b6SLv Zheng 	unsigned long flags;
1016c3a696b6SLv Zheng 
1017c3a696b6SLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
1018c3a696b6SLv Zheng 	ec->busy_polling = true;
1019c3a696b6SLv Zheng 	ec->polling_guard = 0;
1020c3a696b6SLv Zheng 	ec_log_drv("interrupt blocked");
1021c3a696b6SLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
1022c3a696b6SLv Zheng }
1023c3a696b6SLv Zheng 
acpi_ec_leave_noirq(struct acpi_ec * ec)1024c3a696b6SLv Zheng static void acpi_ec_leave_noirq(struct acpi_ec *ec)
1025c3a696b6SLv Zheng {
1026c3a696b6SLv Zheng 	unsigned long flags;
1027c3a696b6SLv Zheng 
1028c3a696b6SLv Zheng 	spin_lock_irqsave(&ec->lock, flags);
1029c3a696b6SLv Zheng 	ec->busy_polling = ec_busy_polling;
1030c3a696b6SLv Zheng 	ec->polling_guard = ec_polling_guard;
1031c3a696b6SLv Zheng 	ec_log_drv("interrupt unblocked");
1032c3a696b6SLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
1033c3a696b6SLv Zheng }
1034c3a696b6SLv Zheng 
acpi_ec_block_transactions(void)1035fe955682SRafael J. Wysocki void acpi_ec_block_transactions(void)
1036f6bb13aaSRafael J. Wysocki {
1037f6bb13aaSRafael J. Wysocki 	struct acpi_ec *ec = first_ec;
1038f6bb13aaSRafael J. Wysocki 
1039f6bb13aaSRafael J. Wysocki 	if (!ec)
1040f6bb13aaSRafael J. Wysocki 		return;
1041f6bb13aaSRafael J. Wysocki 
1042f351d027SFeng Tang 	mutex_lock(&ec->mutex);
1043f6bb13aaSRafael J. Wysocki 	/* Prevent transactions from being carried out */
1044ad479e7fSLv Zheng 	acpi_ec_stop(ec, true);
1045f351d027SFeng Tang 	mutex_unlock(&ec->mutex);
1046f6bb13aaSRafael J. Wysocki }
1047f6bb13aaSRafael J. Wysocki 
acpi_ec_unblock_transactions(void)1048fe955682SRafael J. Wysocki void acpi_ec_unblock_transactions(void)
1049f6bb13aaSRafael J. Wysocki {
1050d5a64513SRafael J. Wysocki 	/*
1051d5a64513SRafael J. Wysocki 	 * Allow transactions to happen again (this function is called from
1052d5a64513SRafael J. Wysocki 	 * atomic context during wakeup, so we don't need to acquire the mutex).
1053d5a64513SRafael J. Wysocki 	 */
1054d5a64513SRafael J. Wysocki 	if (first_ec)
1055ad479e7fSLv Zheng 		acpi_ec_start(first_ec, true);
1056d5a64513SRafael J. Wysocki }
1057d5a64513SRafael J. Wysocki 
10581da177e4SLinus Torvalds /* --------------------------------------------------------------------------
10591da177e4SLinus Torvalds                                 Event Management
10601da177e4SLinus Torvalds    -------------------------------------------------------------------------- */
106101305d41SLv Zheng static struct acpi_ec_query_handler *
acpi_ec_get_query_handler_by_value(struct acpi_ec * ec,u8 value)10620700c047SLv Zheng acpi_ec_get_query_handler_by_value(struct acpi_ec *ec, u8 value)
10630700c047SLv Zheng {
10640700c047SLv Zheng 	struct acpi_ec_query_handler *handler;
10650700c047SLv Zheng 
10660700c047SLv Zheng 	mutex_lock(&ec->mutex);
10670700c047SLv Zheng 	list_for_each_entry(handler, &ec->list, node) {
10680700c047SLv Zheng 		if (value == handler->query_bit) {
10693df663a1SRafael J. Wysocki 			kref_get(&handler->kref);
10703df663a1SRafael J. Wysocki 			mutex_unlock(&ec->mutex);
10713df663a1SRafael J. Wysocki 			return handler;
10720700c047SLv Zheng 		}
10730700c047SLv Zheng 	}
10740700c047SLv Zheng 	mutex_unlock(&ec->mutex);
10753df663a1SRafael J. Wysocki 	return NULL;
10760700c047SLv Zheng }
10770700c047SLv Zheng 
acpi_ec_query_handler_release(struct kref * kref)107801305d41SLv Zheng static void acpi_ec_query_handler_release(struct kref *kref)
107901305d41SLv Zheng {
108001305d41SLv Zheng 	struct acpi_ec_query_handler *handler =
108101305d41SLv Zheng 		container_of(kref, struct acpi_ec_query_handler, kref);
108201305d41SLv Zheng 
108301305d41SLv Zheng 	kfree(handler);
108401305d41SLv Zheng }
108501305d41SLv Zheng 
acpi_ec_put_query_handler(struct acpi_ec_query_handler * handler)108601305d41SLv Zheng static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
108701305d41SLv Zheng {
108801305d41SLv Zheng 	kref_put(&handler->kref, acpi_ec_query_handler_release);
108901305d41SLv Zheng }
109001305d41SLv Zheng 
acpi_ec_add_query_handler(struct acpi_ec * ec,u8 query_bit,acpi_handle handle,acpi_ec_query_func func,void * data)1091837012edSAlexey Starikovskiy int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
1092837012edSAlexey Starikovskiy 			      acpi_handle handle, acpi_ec_query_func func,
1093837012edSAlexey Starikovskiy 			      void *data)
1094837012edSAlexey Starikovskiy {
109528f7b858SArmin Wolf 	struct acpi_ec_query_handler *handler;
10967a73e60eSLv Zheng 
109728f7b858SArmin Wolf 	if (!handle && !func)
109828f7b858SArmin Wolf 		return -EINVAL;
109928f7b858SArmin Wolf 
110028f7b858SArmin Wolf 	handler = kzalloc(sizeof(*handler), GFP_KERNEL);
1101837012edSAlexey Starikovskiy 	if (!handler)
1102837012edSAlexey Starikovskiy 		return -ENOMEM;
1103837012edSAlexey Starikovskiy 
1104837012edSAlexey Starikovskiy 	handler->query_bit = query_bit;
1105837012edSAlexey Starikovskiy 	handler->handle = handle;
1106837012edSAlexey Starikovskiy 	handler->func = func;
1107837012edSAlexey Starikovskiy 	handler->data = data;
1108f351d027SFeng Tang 	mutex_lock(&ec->mutex);
110901305d41SLv Zheng 	kref_init(&handler->kref);
111030c08574SAlexey Starikovskiy 	list_add(&handler->node, &ec->list);
1111f351d027SFeng Tang 	mutex_unlock(&ec->mutex);
111228f7b858SArmin Wolf 
1113837012edSAlexey Starikovskiy 	return 0;
1114837012edSAlexey Starikovskiy }
1115837012edSAlexey Starikovskiy EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
1116837012edSAlexey Starikovskiy 
acpi_ec_remove_query_handlers(struct acpi_ec * ec,bool remove_all,u8 query_bit)11170700c047SLv Zheng static void acpi_ec_remove_query_handlers(struct acpi_ec *ec,
11180700c047SLv Zheng 					  bool remove_all, u8 query_bit)
1119837012edSAlexey Starikovskiy {
11201544fdbcSAdrian Bunk 	struct acpi_ec_query_handler *handler, *tmp;
112101305d41SLv Zheng 	LIST_HEAD(free_list);
11227a73e60eSLv Zheng 
1123f351d027SFeng Tang 	mutex_lock(&ec->mutex);
11241544fdbcSAdrian Bunk 	list_for_each_entry_safe(handler, tmp, &ec->list, node) {
112528f7b858SArmin Wolf 		/*
112628f7b858SArmin Wolf 		 * When remove_all is false, only remove custom query handlers
112728f7b858SArmin Wolf 		 * which have handler->func set. This is done to preserve query
112828f7b858SArmin Wolf 		 * handlers discovered thru ACPI, as they should continue handling
112928f7b858SArmin Wolf 		 * EC queries.
113028f7b858SArmin Wolf 		 */
113128f7b858SArmin Wolf 		if (remove_all || (handler->func && handler->query_bit == query_bit)) {
113201305d41SLv Zheng 			list_del_init(&handler->node);
113301305d41SLv Zheng 			list_add(&handler->node, &free_list);
113428f7b858SArmin Wolf 
1135837012edSAlexey Starikovskiy 		}
1136837012edSAlexey Starikovskiy 	}
1137f351d027SFeng Tang 	mutex_unlock(&ec->mutex);
11386b5eab54SChris Bainbridge 	list_for_each_entry_safe(handler, tmp, &free_list, node)
113901305d41SLv Zheng 		acpi_ec_put_query_handler(handler);
1140837012edSAlexey Starikovskiy }
11410700c047SLv Zheng 
acpi_ec_remove_query_handler(struct acpi_ec * ec,u8 query_bit)11420700c047SLv Zheng void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
11430700c047SLv Zheng {
11440700c047SLv Zheng 	acpi_ec_remove_query_handlers(ec, false, query_bit);
1145e5b492c6SArmin Wolf 	flush_workqueue(ec_query_wq);
11460700c047SLv Zheng }
1147837012edSAlexey Starikovskiy EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
11481da177e4SLinus Torvalds 
acpi_ec_event_processor(struct work_struct * work)114902b771b6SLv Zheng static void acpi_ec_event_processor(struct work_struct *work)
115002b771b6SLv Zheng {
115102b771b6SLv Zheng 	struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work);
115202b771b6SLv Zheng 	struct acpi_ec_query_handler *handler = q->handler;
11534a9af6caSRafael J. Wysocki 	struct acpi_ec *ec = q->ec;
115402b771b6SLv Zheng 
11553535a3c1SLv Zheng 	ec_dbg_evt("Query(0x%02x) started", handler->query_bit);
11564a9af6caSRafael J. Wysocki 
1157a62e8f19SAlexey Starikovskiy 	if (handler->func)
1158a62e8f19SAlexey Starikovskiy 		handler->func(handler->data);
1159a62e8f19SAlexey Starikovskiy 	else if (handler->handle)
1160a62e8f19SAlexey Starikovskiy 		acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
11614a9af6caSRafael J. Wysocki 
11623535a3c1SLv Zheng 	ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit);
11634a9af6caSRafael J. Wysocki 
11644a9af6caSRafael J. Wysocki 	spin_lock_irq(&ec->lock);
11654a9af6caSRafael J. Wysocki 	ec->queries_in_progress--;
11664a9af6caSRafael J. Wysocki 	spin_unlock_irq(&ec->lock);
11674a9af6caSRafael J. Wysocki 
1168befd9b5bSRafael J. Wysocki 	acpi_ec_put_query_handler(handler);
1169befd9b5bSRafael J. Wysocki 	kfree(q);
1170befd9b5bSRafael J. Wysocki }
1171befd9b5bSRafael J. Wysocki 
acpi_ec_create_query(struct acpi_ec * ec,u8 * pval)1172befd9b5bSRafael J. Wysocki static struct acpi_ec_query *acpi_ec_create_query(struct acpi_ec *ec, u8 *pval)
1173befd9b5bSRafael J. Wysocki {
1174befd9b5bSRafael J. Wysocki 	struct acpi_ec_query *q;
1175befd9b5bSRafael J. Wysocki 	struct transaction *t;
1176befd9b5bSRafael J. Wysocki 
1177befd9b5bSRafael J. Wysocki 	q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL);
1178befd9b5bSRafael J. Wysocki 	if (!q)
1179befd9b5bSRafael J. Wysocki 		return NULL;
1180befd9b5bSRafael J. Wysocki 
1181befd9b5bSRafael J. Wysocki 	INIT_WORK(&q->work, acpi_ec_event_processor);
1182befd9b5bSRafael J. Wysocki 	t = &q->transaction;
1183befd9b5bSRafael J. Wysocki 	t->command = ACPI_EC_COMMAND_QUERY;
1184befd9b5bSRafael J. Wysocki 	t->rdata = pval;
1185befd9b5bSRafael J. Wysocki 	t->rlen = 1;
1186befd9b5bSRafael J. Wysocki 	q->ec = ec;
1187befd9b5bSRafael J. Wysocki 	return q;
1188a62e8f19SAlexey Starikovskiy }
1189a62e8f19SAlexey Starikovskiy 
acpi_ec_submit_query(struct acpi_ec * ec)1190eafe7509SRafael J. Wysocki static int acpi_ec_submit_query(struct acpi_ec *ec)
1191a62e8f19SAlexey Starikovskiy {
11921f235044SRafael J. Wysocki 	struct acpi_ec_query *q;
1193a62e8f19SAlexey Starikovskiy 	u8 value = 0;
1194c2cf5769SLv Zheng 	int result;
119502b771b6SLv Zheng 
11964a9af6caSRafael J. Wysocki 	q = acpi_ec_create_query(ec, &value);
119702b771b6SLv Zheng 	if (!q)
119802b771b6SLv Zheng 		return -ENOMEM;
11993eba563eSKieran Clancy 
1200550b3aacSLv Zheng 	/*
1201550b3aacSLv Zheng 	 * Query the EC to find out which _Qxx method we need to evaluate.
1202550b3aacSLv Zheng 	 * Note that successful completion of the query causes the ACPI_EC_SCI
1203550b3aacSLv Zheng 	 * bit to be cleared (and thus clearing the interrupt source).
1204550b3aacSLv Zheng 	 */
120502b771b6SLv Zheng 	result = acpi_ec_transaction(ec, &q->transaction);
120602b771b6SLv Zheng 	if (result)
120702b771b6SLv Zheng 		goto err_exit;
12083eba563eSKieran Clancy 
12091f235044SRafael J. Wysocki 	if (!value) {
12101f235044SRafael J. Wysocki 		result = -ENODATA;
12111f235044SRafael J. Wysocki 		goto err_exit;
12121f235044SRafael J. Wysocki 	}
12131f235044SRafael J. Wysocki 
12140700c047SLv Zheng 	q->handler = acpi_ec_get_query_handler_by_value(ec, value);
12150700c047SLv Zheng 	if (!q->handler) {
121615b94fa3SLv Zheng 		result = -ENODATA;
12170700c047SLv Zheng 		goto err_exit;
12180700c047SLv Zheng 	}
12190700c047SLv Zheng 
122002b771b6SLv Zheng 	/*
12214a9af6caSRafael J. Wysocki 	 * It is reported that _Qxx are evaluated in a parallel way on Windows:
122202b771b6SLv Zheng 	 * https://bugzilla.kernel.org/show_bug.cgi?id=94411
12230700c047SLv Zheng 	 *
12244a9af6caSRafael J. Wysocki 	 * Put this log entry before queue_work() to make it appear in the log
12254a9af6caSRafael J. Wysocki 	 * before any other messages emitted during workqueue handling.
122602b771b6SLv Zheng 	 */
12270700c047SLv Zheng 	ec_dbg_evt("Query(0x%02x) scheduled", value);
12284a9af6caSRafael J. Wysocki 
12294a9af6caSRafael J. Wysocki 	spin_lock_irq(&ec->lock);
12304a9af6caSRafael J. Wysocki 
12314a9af6caSRafael J. Wysocki 	ec->queries_in_progress++;
12324a9af6caSRafael J. Wysocki 	queue_work(ec_query_wq, &q->work);
12334a9af6caSRafael J. Wysocki 
12344a9af6caSRafael J. Wysocki 	spin_unlock_irq(&ec->lock);
123502b771b6SLv Zheng 
1236befd9b5bSRafael J. Wysocki 	return 0;
1237befd9b5bSRafael J. Wysocki 
123802b771b6SLv Zheng err_exit:
1239befd9b5bSRafael J. Wysocki 	kfree(q);
12401f235044SRafael J. Wysocki 
1241c2cf5769SLv Zheng 	return result;
1242a62e8f19SAlexey Starikovskiy }
1243a62e8f19SAlexey Starikovskiy 
acpi_ec_event_handler(struct work_struct * work)12449d8993beSLv Zheng static void acpi_ec_event_handler(struct work_struct *work)
1245a62e8f19SAlexey Starikovskiy {
124674443bbeSLv Zheng 	struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
12477a73e60eSLv Zheng 
12489d8993beSLv Zheng 	ec_dbg_evt("Event started");
12499d8993beSLv Zheng 
1250a105acd7SRafael J. Wysocki 	spin_lock_irq(&ec->lock);
1251a105acd7SRafael J. Wysocki 
1252c793570dSRafael J. Wysocki 	while (ec->events_to_process) {
1253a105acd7SRafael J. Wysocki 		spin_unlock_irq(&ec->lock);
12541f235044SRafael J. Wysocki 
1255eafe7509SRafael J. Wysocki 		acpi_ec_submit_query(ec);
12561f235044SRafael J. Wysocki 
1257a105acd7SRafael J. Wysocki 		spin_lock_irq(&ec->lock);
125813a62d0eSRafael J. Wysocki 
1259c793570dSRafael J. Wysocki 		ec->events_to_process--;
1260388fb77dSRafael J. Wysocki 	}
1261388fb77dSRafael J. Wysocki 
126266db3834SLv Zheng 	/*
1263388fb77dSRafael J. Wysocki 	 * Before exit, make sure that the it will be possible to queue up the
1264388fb77dSRafael J. Wysocki 	 * event handling work again regardless of whether or not the query
1265388fb77dSRafael J. Wysocki 	 * queued up above is processed successfully.
126666db3834SLv Zheng 	 */
126713a62d0eSRafael J. Wysocki 	if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
126813a62d0eSRafael J. Wysocki 		bool guard_timeout;
1269388fb77dSRafael J. Wysocki 
127013a62d0eSRafael J. Wysocki 		acpi_ec_complete_event(ec);
12719d8993beSLv Zheng 
12729d8993beSLv Zheng 		ec_dbg_evt("Event stopped");
12731d68d261SLv Zheng 
127413a62d0eSRafael J. Wysocki 		spin_unlock_irq(&ec->lock);
127513a62d0eSRafael J. Wysocki 
127613a62d0eSRafael J. Wysocki 		guard_timeout = !!ec_guard(ec);
127713a62d0eSRafael J. Wysocki 
1278a105acd7SRafael J. Wysocki 		spin_lock_irq(&ec->lock);
127998d36450SRafael J. Wysocki 
128098d36450SRafael J. Wysocki 		/* Take care of SCI_EVT unless someone else is doing that. */
128113a62d0eSRafael J. Wysocki 		if (guard_timeout && !ec->curr)
128298d36450SRafael J. Wysocki 			advance_transaction(ec, false);
128313a62d0eSRafael J. Wysocki 	} else {
128413a62d0eSRafael J. Wysocki 		acpi_ec_close_event(ec);
128598d36450SRafael J. Wysocki 
128613a62d0eSRafael J. Wysocki 		ec_dbg_evt("Event stopped");
128798d36450SRafael J. Wysocki 	}
12884a9af6caSRafael J. Wysocki 
12894a9af6caSRafael J. Wysocki 	ec->events_in_progress--;
129013a62d0eSRafael J. Wysocki 
1291a105acd7SRafael J. Wysocki 	spin_unlock_irq(&ec->lock);
129245bea155SLuming Yu }
12931da177e4SLinus Torvalds 
clear_gpe_and_advance_transaction(struct acpi_ec * ec,bool interrupt)1294b5539eb5SRafael J. Wysocki static void clear_gpe_and_advance_transaction(struct acpi_ec *ec, bool interrupt)
12951da177e4SLinus Torvalds {
1296896e97bfSCompostella, Jeremy 	/*
1297896e97bfSCompostella, Jeremy 	 * Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
1298896e97bfSCompostella, Jeremy 	 * changes to always trigger a GPE interrupt.
1299896e97bfSCompostella, Jeremy 	 *
1300896e97bfSCompostella, Jeremy 	 * GPE STS is a W1C register, which means:
1301896e97bfSCompostella, Jeremy 	 *
1302896e97bfSCompostella, Jeremy 	 * 1. Software can clear it without worrying about clearing the other
1303896e97bfSCompostella, Jeremy 	 *    GPEs' STS bits when the hardware sets them in parallel.
1304896e97bfSCompostella, Jeremy 	 *
1305896e97bfSCompostella, Jeremy 	 * 2. As long as software can ensure only clearing it when it is set,
1306896e97bfSCompostella, Jeremy 	 *    hardware won't set it in parallel.
1307896e97bfSCompostella, Jeremy 	 */
1308896e97bfSCompostella, Jeremy 	if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
1309896e97bfSCompostella, Jeremy 		acpi_clear_gpe(NULL, ec->gpe);
1310896e97bfSCompostella, Jeremy 
13112e84ea5aSSebastian Andrzej Siewior 	advance_transaction(ec, true);
1312b5539eb5SRafael J. Wysocki }
1313b5539eb5SRafael J. Wysocki 
acpi_ec_handle_interrupt(struct acpi_ec * ec)1314b5539eb5SRafael J. Wysocki static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
1315b5539eb5SRafael J. Wysocki {
1316b5539eb5SRafael J. Wysocki 	unsigned long flags;
1317b5539eb5SRafael J. Wysocki 
1318b5539eb5SRafael J. Wysocki 	spin_lock_irqsave(&ec->lock, flags);
1319b5539eb5SRafael J. Wysocki 
1320b5539eb5SRafael J. Wysocki 	clear_gpe_and_advance_transaction(ec, true);
1321b5539eb5SRafael J. Wysocki 
1322c0d65341SLv Zheng 	spin_unlock_irqrestore(&ec->lock, flags);
1323406857f7SDaniel Drake }
1324406857f7SDaniel Drake 
acpi_ec_gpe_handler(acpi_handle gpe_device,u32 gpe_number,void * data)1325406857f7SDaniel Drake static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
1326406857f7SDaniel Drake 			       u32 gpe_number, void *data)
1327406857f7SDaniel Drake {
1328406857f7SDaniel Drake 	acpi_ec_handle_interrupt(data);
1329ca37bfdfSLv Zheng 	return ACPI_INTERRUPT_HANDLED;
1330845625cdSAlexey Starikovskiy }
1331845625cdSAlexey Starikovskiy 
acpi_ec_irq_handler(int irq,void * data)1332406857f7SDaniel Drake static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
1333406857f7SDaniel Drake {
1334406857f7SDaniel Drake 	acpi_ec_handle_interrupt(data);
1335406857f7SDaniel Drake 	return IRQ_HANDLED;
1336406857f7SDaniel Drake }
1337406857f7SDaniel Drake 
13381da177e4SLinus Torvalds /* --------------------------------------------------------------------------
13397a73e60eSLv Zheng  *                           Address Space Management
13407a73e60eSLv Zheng  * -------------------------------------------------------------------------- */
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds static acpi_status
acpi_ec_space_handler(u32 function,acpi_physical_address address,u32 bits,u64 * value64,void * handler_context,void * region_context)13435b7734b4SAlexey Starikovskiy acpi_ec_space_handler(u32 function, acpi_physical_address address,
1344dadf28a1SAlexey Starikovskiy 		      u32 bits, u64 *value64,
134550526df6SLen Brown 		      void *handler_context, void *region_context)
13461da177e4SLinus Torvalds {
13473d02b90bSAlexey Starikovskiy 	struct acpi_ec *ec = handler_context;
1348dadf28a1SAlexey Starikovskiy 	int result = 0, i, bytes = bits / 8;
1349dadf28a1SAlexey Starikovskiy 	u8 *value = (u8 *)value64;
1350*93d065b7SRafael J. Wysocki 	u32 glk;
13511da177e4SLinus Torvalds 
13521da177e4SLinus Torvalds 	if ((address > 0xFF) || !value || !handler_context)
1353d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
13541da177e4SLinus Torvalds 
13555b7734b4SAlexey Starikovskiy 	if (function != ACPI_READ && function != ACPI_WRITE)
1356d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
13571da177e4SLinus Torvalds 
1358*93d065b7SRafael J. Wysocki 	mutex_lock(&ec->mutex);
1359*93d065b7SRafael J. Wysocki 
1360*93d065b7SRafael J. Wysocki 	if (ec->global_lock) {
1361*93d065b7SRafael J. Wysocki 		acpi_status status;
1362*93d065b7SRafael J. Wysocki 
1363*93d065b7SRafael J. Wysocki 		status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
1364*93d065b7SRafael J. Wysocki 		if (ACPI_FAILURE(status)) {
1365*93d065b7SRafael J. Wysocki 			result = -ENODEV;
1366*93d065b7SRafael J. Wysocki 			goto unlock;
1367*93d065b7SRafael J. Wysocki 		}
1368*93d065b7SRafael J. Wysocki 	}
1369*93d065b7SRafael J. Wysocki 
1370c3a696b6SLv Zheng 	if (ec->busy_polling || bits > 8)
1371b3b233c7SAlexey Starikovskiy 		acpi_ec_burst_enable(ec);
1372b3b233c7SAlexey Starikovskiy 
13735e49b9b5SArmin Wolf 	for (i = 0; i < bytes; ++i, ++address, ++value) {
1374dadf28a1SAlexey Starikovskiy 		result = (function == ACPI_READ) ?
1375*93d065b7SRafael J. Wysocki 			acpi_ec_read_unlocked(ec, address, value) :
1376*93d065b7SRafael J. Wysocki 			acpi_ec_write_unlocked(ec, address, *value);
13775e49b9b5SArmin Wolf 		if (result < 0)
13785e49b9b5SArmin Wolf 			break;
13795e49b9b5SArmin Wolf 	}
13803e71a87dSAlexey Starikovskiy 
1381c3a696b6SLv Zheng 	if (ec->busy_polling || bits > 8)
1382b3b233c7SAlexey Starikovskiy 		acpi_ec_burst_disable(ec);
1383b3b233c7SAlexey Starikovskiy 
1384*93d065b7SRafael J. Wysocki 	if (ec->global_lock)
1385*93d065b7SRafael J. Wysocki 		acpi_release_global_lock(glk);
1386*93d065b7SRafael J. Wysocki 
1387*93d065b7SRafael J. Wysocki unlock:
1388*93d065b7SRafael J. Wysocki 	mutex_unlock(&ec->mutex);
1389*93d065b7SRafael J. Wysocki 
13901da177e4SLinus Torvalds 	switch (result) {
13911da177e4SLinus Torvalds 	case -EINVAL:
1392d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
13931da177e4SLinus Torvalds 	case -ENODEV:
1394d550d98dSPatrick Mochel 		return AE_NOT_FOUND;
13951da177e4SLinus Torvalds 	case -ETIME:
1396d550d98dSPatrick Mochel 		return AE_TIME;
1397a0156b83SArmin Wolf 	case 0:
1398d550d98dSPatrick Mochel 		return AE_OK;
1399a0156b83SArmin Wolf 	default:
1400a0156b83SArmin Wolf 		return AE_ERROR;
14011da177e4SLinus Torvalds 	}
14021da177e4SLinus Torvalds }
14031da177e4SLinus Torvalds 
14041da177e4SLinus Torvalds /* --------------------------------------------------------------------------
14057a73e60eSLv Zheng  *                             Driver Interface
14067a73e60eSLv Zheng  * -------------------------------------------------------------------------- */
14077a73e60eSLv Zheng 
1408c0900c35SAlexey Starikovskiy static acpi_status
1409c0900c35SAlexey Starikovskiy ec_parse_io_ports(struct acpi_resource *resource, void *context);
1410c0900c35SAlexey Starikovskiy 
acpi_ec_free(struct acpi_ec * ec)141172c77b7eSLv Zheng static void acpi_ec_free(struct acpi_ec *ec)
141272c77b7eSLv Zheng {
141372c77b7eSLv Zheng 	if (first_ec == ec)
141472c77b7eSLv Zheng 		first_ec = NULL;
141572c77b7eSLv Zheng 	if (boot_ec == ec)
141672c77b7eSLv Zheng 		boot_ec = NULL;
141772c77b7eSLv Zheng 	kfree(ec);
141872c77b7eSLv Zheng }
141972c77b7eSLv Zheng 
acpi_ec_alloc(void)142072c77b7eSLv Zheng static struct acpi_ec *acpi_ec_alloc(void)
1421c0900c35SAlexey Starikovskiy {
1422c0900c35SAlexey Starikovskiy 	struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
14237a73e60eSLv Zheng 
1424c0900c35SAlexey Starikovskiy 	if (!ec)
1425c0900c35SAlexey Starikovskiy 		return NULL;
1426f351d027SFeng Tang 	mutex_init(&ec->mutex);
1427c0900c35SAlexey Starikovskiy 	init_waitqueue_head(&ec->wait);
1428837012edSAlexey Starikovskiy 	INIT_LIST_HEAD(&ec->list);
1429f351d027SFeng Tang 	spin_lock_init(&ec->lock);
14309d8993beSLv Zheng 	INIT_WORK(&ec->work, acpi_ec_event_handler);
1431d8d031a6SLv Zheng 	ec->timestamp = jiffies;
1432c3a696b6SLv Zheng 	ec->busy_polling = true;
1433c3a696b6SLv Zheng 	ec->polling_guard = 0;
1434406857f7SDaniel Drake 	ec->gpe = -1;
1435406857f7SDaniel Drake 	ec->irq = -1;
1436c0900c35SAlexey Starikovskiy 	return ec;
1437c0900c35SAlexey Starikovskiy }
14381da177e4SLinus Torvalds 
1439837012edSAlexey Starikovskiy static acpi_status
acpi_ec_register_query_methods(acpi_handle handle,u32 level,void * context,void ** return_value)1440c019b193SAlexey Starikovskiy acpi_ec_register_query_methods(acpi_handle handle, u32 level,
1441c019b193SAlexey Starikovskiy 			       void *context, void **return_value)
1442c019b193SAlexey Starikovskiy {
14430175d562SLin Ming 	char node_name[5];
14440175d562SLin Ming 	struct acpi_buffer buffer = { sizeof(node_name), node_name };
1445c019b193SAlexey Starikovskiy 	struct acpi_ec *ec = context;
1446c019b193SAlexey Starikovskiy 	int value = 0;
14470175d562SLin Ming 	acpi_status status;
14480175d562SLin Ming 
14490175d562SLin Ming 	status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
14500175d562SLin Ming 
14517a73e60eSLv Zheng 	if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1)
1452c019b193SAlexey Starikovskiy 		acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
1453c019b193SAlexey Starikovskiy 	return AE_OK;
1454c019b193SAlexey Starikovskiy }
1455c019b193SAlexey Starikovskiy 
1456c019b193SAlexey Starikovskiy static acpi_status
ec_parse_device(acpi_handle handle,u32 Level,void * context,void ** retval)1457cd8c93a4SAlexey Starikovskiy ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
1458837012edSAlexey Starikovskiy {
1459cd8c93a4SAlexey Starikovskiy 	acpi_status status;
1460d21cf3c1SAlexey Starikovskiy 	unsigned long long tmp = 0;
1461cd8c93a4SAlexey Starikovskiy 	struct acpi_ec *ec = context;
1462a5032bfdSAlexey Starikovskiy 
1463a5032bfdSAlexey Starikovskiy 	/* clear addr values, ec_parse_io_ports depend on it */
1464a5032bfdSAlexey Starikovskiy 	ec->command_addr = ec->data_addr = 0;
1465a5032bfdSAlexey Starikovskiy 
1466cd8c93a4SAlexey Starikovskiy 	status = acpi_walk_resources(handle, METHOD_NAME__CRS,
1467cd8c93a4SAlexey Starikovskiy 				     ec_parse_io_ports, ec);
1468cd8c93a4SAlexey Starikovskiy 	if (ACPI_FAILURE(status))
1469cd8c93a4SAlexey Starikovskiy 		return status;
1470ae56c9fdSLv Zheng 	if (ec->data_addr == 0 || ec->command_addr == 0)
1471ae56c9fdSLv Zheng 		return AE_OK;
1472837012edSAlexey Starikovskiy 
1473837012edSAlexey Starikovskiy 	/* Get GPE bit assignment (EC events). */
1474837012edSAlexey Starikovskiy 	/* TODO: Add support for _GPE returning a package */
147527663c58SMatthew Wilcox 	status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
1476406857f7SDaniel Drake 	if (ACPI_SUCCESS(status))
147727663c58SMatthew Wilcox 		ec->gpe = tmp;
1478406857f7SDaniel Drake 	/*
1479406857f7SDaniel Drake 	 * Errors are non-fatal, allowing for ACPI Reduced Hardware
1480406857f7SDaniel Drake 	 * platforms which use GpioInt instead of GPE.
1481406857f7SDaniel Drake 	 */
1482f7090e0eSHans de Goede 
1483837012edSAlexey Starikovskiy 	/* Use the global lock for all EC transactions? */
1484d21cf3c1SAlexey Starikovskiy 	tmp = 0;
148527663c58SMatthew Wilcox 	acpi_evaluate_integer(handle, "_GLK", NULL, &tmp);
148627663c58SMatthew Wilcox 	ec->global_lock = tmp;
1487837012edSAlexey Starikovskiy 	ec->handle = handle;
1488cd8c93a4SAlexey Starikovskiy 	return AE_CTRL_TERMINATE;
1489837012edSAlexey Starikovskiy }
1490837012edSAlexey Starikovskiy 
install_gpe_event_handler(struct acpi_ec * ec)149103e9a0e0SRafael J. Wysocki static bool install_gpe_event_handler(struct acpi_ec *ec)
1492406857f7SDaniel Drake {
149303e9a0e0SRafael J. Wysocki 	acpi_status status;
149403e9a0e0SRafael J. Wysocki 
149503e9a0e0SRafael J. Wysocki 	status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
1496406857f7SDaniel Drake 					      ACPI_GPE_EDGE_TRIGGERED,
149703e9a0e0SRafael J. Wysocki 					      &acpi_ec_gpe_handler, ec);
149803e9a0e0SRafael J. Wysocki 	if (ACPI_FAILURE(status))
149903e9a0e0SRafael J. Wysocki 		return false;
150003e9a0e0SRafael J. Wysocki 
150103e9a0e0SRafael J. Wysocki 	if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1)
1502406857f7SDaniel Drake 		acpi_ec_enable_gpe(ec, true);
150303e9a0e0SRafael J. Wysocki 
150403e9a0e0SRafael J. Wysocki 	return true;
1505406857f7SDaniel Drake }
1506406857f7SDaniel Drake 
install_gpio_irq_event_handler(struct acpi_ec * ec)150703e9a0e0SRafael J. Wysocki static bool install_gpio_irq_event_handler(struct acpi_ec *ec)
1508406857f7SDaniel Drake {
150903e9a0e0SRafael J. Wysocki 	return request_irq(ec->irq, acpi_ec_irq_handler, IRQF_SHARED,
151003e9a0e0SRafael J. Wysocki 			   "ACPI EC", ec) >= 0;
1511406857f7SDaniel Drake }
1512406857f7SDaniel Drake 
151303e9a0e0SRafael J. Wysocki /**
151403e9a0e0SRafael J. Wysocki  * ec_install_handlers - Install service callbacks and register query methods.
151503e9a0e0SRafael J. Wysocki  * @ec: Target EC.
151603e9a0e0SRafael J. Wysocki  * @device: ACPI device object corresponding to @ec.
1517ab4620f5SHans de Goede  * @call_reg: If _REG should be called to notify OpRegion availability
151803e9a0e0SRafael J. Wysocki  *
151903e9a0e0SRafael J. Wysocki  * Install a handler for the EC address space type unless it has been installed
152003e9a0e0SRafael J. Wysocki  * already.  If @device is not NULL, also look for EC query methods in the
152103e9a0e0SRafael J. Wysocki  * namespace and register them, and install an event (either GPE or GPIO IRQ)
152203e9a0e0SRafael J. Wysocki  * handler for the EC, if possible.
152303e9a0e0SRafael J. Wysocki  *
152403e9a0e0SRafael J. Wysocki  * Return:
152503e9a0e0SRafael J. Wysocki  * -ENODEV if the address space handler cannot be installed, which means
152603e9a0e0SRafael J. Wysocki  *  "unable to handle transactions",
152703e9a0e0SRafael J. Wysocki  * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred,
152803e9a0e0SRafael J. Wysocki  * or 0 (success) otherwise.
152972c77b7eSLv Zheng  */
ec_install_handlers(struct acpi_ec * ec,struct acpi_device * device,bool call_reg)1530ab4620f5SHans de Goede static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
1531ab4620f5SHans de Goede 			       bool call_reg)
1532e8284321SAlexey Starikovskiy {
1533c0900c35SAlexey Starikovskiy 	acpi_status status;
15347a73e60eSLv Zheng 
1535ad479e7fSLv Zheng 	acpi_ec_start(ec, false);
15360e1affe4SLv Zheng 
15370e1affe4SLv Zheng 	if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
1538d2c76802SRafael J. Wysocki 		acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle;
1539d2c76802SRafael J. Wysocki 
1540c3a696b6SLv Zheng 		acpi_ec_enter_noirq(ec);
154196a0e06dSRafael J. Wysocki 		status = acpi_install_address_space_handler_no_reg(scope_handle,
1542e8284321SAlexey Starikovskiy 								   ACPI_ADR_SPACE_EC,
1543e8284321SAlexey Starikovskiy 								   &acpi_ec_space_handler,
15446d9e1120SAlexey Starikovskiy 								   NULL, ec);
1545e8284321SAlexey Starikovskiy 		if (ACPI_FAILURE(status)) {
1546ad479e7fSLv Zheng 			acpi_ec_stop(ec, false);
1547e8284321SAlexey Starikovskiy 			return -ENODEV;
1548e8284321SAlexey Starikovskiy 		}
15490e1affe4SLv Zheng 		set_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
15500e1affe4SLv Zheng 	}
1551e8284321SAlexey Starikovskiy 
1552ab4620f5SHans de Goede 	if (call_reg && !test_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags)) {
1553d2c76802SRafael J. Wysocki 		acpi_execute_reg_methods(ec->handle, ACPI_UINT32_MAX, ACPI_ADR_SPACE_EC);
1554ab4620f5SHans de Goede 		set_bit(EC_FLAGS_EC_REG_CALLED, &ec->flags);
15551da177e4SLinus Torvalds 	}
1556d550d98dSPatrick Mochel 
1557a2b69177SRafael J. Wysocki 	if (!device)
15582a570840SLv Zheng 		return 0;
15592a570840SLv Zheng 
156003e9a0e0SRafael J. Wysocki 	if (ec->gpe < 0) {
156103e9a0e0SRafael J. Wysocki 		/* ACPI reduced hardware platforms use a GpioInt from _CRS. */
156203e9a0e0SRafael J. Wysocki 		int irq = acpi_dev_gpio_irq_get(device, 0);
156303e9a0e0SRafael J. Wysocki 		/*
156403e9a0e0SRafael J. Wysocki 		 * Bail out right away for deferred probing or complete the
156503e9a0e0SRafael J. Wysocki 		 * initialization regardless of any other errors.
156603e9a0e0SRafael J. Wysocki 		 */
156703e9a0e0SRafael J. Wysocki 		if (irq == -EPROBE_DEFER)
156803e9a0e0SRafael J. Wysocki 			return -EPROBE_DEFER;
156903e9a0e0SRafael J. Wysocki 		else if (irq >= 0)
157003e9a0e0SRafael J. Wysocki 			ec->irq = irq;
157103e9a0e0SRafael J. Wysocki 	}
157203e9a0e0SRafael J. Wysocki 
15734446abc9SDaniel Drake 	if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
15742a570840SLv Zheng 		/* Find and register all query methods */
15752a570840SLv Zheng 		acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
15762a570840SLv Zheng 				    acpi_ec_register_query_methods,
15772a570840SLv Zheng 				    NULL, ec, NULL);
15784446abc9SDaniel Drake 		set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
15792a570840SLv Zheng 	}
15804446abc9SDaniel Drake 	if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
158103e9a0e0SRafael J. Wysocki 		bool ready = false;
1582406857f7SDaniel Drake 
158303e9a0e0SRafael J. Wysocki 		if (ec->gpe >= 0)
158403e9a0e0SRafael J. Wysocki 			ready = install_gpe_event_handler(ec);
158503e9a0e0SRafael J. Wysocki 		else if (ec->irq >= 0)
158603e9a0e0SRafael J. Wysocki 			ready = install_gpio_irq_event_handler(ec);
158703e9a0e0SRafael J. Wysocki 
158803e9a0e0SRafael J. Wysocki 		if (ready) {
158903e9a0e0SRafael J. Wysocki 			set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
159003e9a0e0SRafael J. Wysocki 			acpi_ec_leave_noirq(ec);
159153c5eaabSLv Zheng 		}
159203e9a0e0SRafael J. Wysocki 		/*
159303e9a0e0SRafael J. Wysocki 		 * Failures to install an event handler are not fatal, because
159403e9a0e0SRafael J. Wysocki 		 * the EC can be polled for events.
159503e9a0e0SRafael J. Wysocki 		 */
159653c5eaabSLv Zheng 	}
15972a570840SLv Zheng 	/* EC is fully operational, allow queries */
15982a570840SLv Zheng 	acpi_ec_enable_event(ec);
15990e1affe4SLv Zheng 
16001da177e4SLinus Torvalds 	return 0;
16011da177e4SLinus Torvalds }
16021da177e4SLinus Torvalds 
ec_remove_handlers(struct acpi_ec * ec)16031da177e4SLinus Torvalds static void ec_remove_handlers(struct acpi_ec *ec)
16041da177e4SLinus Torvalds {
160596a0e06dSRafael J. Wysocki 	acpi_handle scope_handle = ec == first_ec ? ACPI_ROOT_OBJECT : ec->handle;
160696a0e06dSRafael J. Wysocki 
16070e1affe4SLv Zheng 	if (test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) {
1608a5072078SHans de Goede 		if (ACPI_FAILURE(acpi_remove_address_space_handler(
160996a0e06dSRafael J. Wysocki 						scope_handle,
161096a0e06dSRafael J. Wysocki 						ACPI_ADR_SPACE_EC,
161196a0e06dSRafael J. Wysocki 						&acpi_ec_space_handler)))
161216a26e85SLan Tianyu 			pr_err("failed to remove space handler\n");
16130e1affe4SLv Zheng 		clear_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags);
16140e1affe4SLv Zheng 	}
16150e1affe4SLv Zheng 
1616fa5b4a50SLv Zheng 	/*
1617fa5b4a50SLv Zheng 	 * Stops handling the EC transactions after removing the operation
1618fa5b4a50SLv Zheng 	 * region handler. This is required because _REG(DISCONNECT)
1619fa5b4a50SLv Zheng 	 * invoked during the removal can result in new EC transactions.
1620fa5b4a50SLv Zheng 	 *
1621fa5b4a50SLv Zheng 	 * Flushes the EC requests and thus disables the GPE before
1622fa5b4a50SLv Zheng 	 * removing the GPE handler. This is required by the current ACPICA
1623fa5b4a50SLv Zheng 	 * GPE core. ACPICA GPE core will automatically disable a GPE when
1624fa5b4a50SLv Zheng 	 * it is indicated but there is no way to handle it. So the drivers
1625fa5b4a50SLv Zheng 	 * must disable the GPEs prior to removing the GPE handlers.
1626fa5b4a50SLv Zheng 	 */
1627fa5b4a50SLv Zheng 	acpi_ec_stop(ec, false);
1628fa5b4a50SLv Zheng 
16294446abc9SDaniel Drake 	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
1630406857f7SDaniel Drake 		if (ec->gpe >= 0 &&
1631406857f7SDaniel Drake 		    ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
16321da177e4SLinus Torvalds 				 &acpi_ec_gpe_handler)))
163316a26e85SLan Tianyu 			pr_err("failed to remove gpe handler\n");
1634406857f7SDaniel Drake 
1635406857f7SDaniel Drake 		if (ec->irq >= 0)
1636406857f7SDaniel Drake 			free_irq(ec->irq, ec);
1637406857f7SDaniel Drake 
16384446abc9SDaniel Drake 		clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
16390e1affe4SLv Zheng 	}
16404446abc9SDaniel Drake 	if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
16412a570840SLv Zheng 		acpi_ec_remove_query_handlers(ec, true, 0);
16424446abc9SDaniel Drake 		clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
16432a570840SLv Zheng 	}
16441da177e4SLinus Torvalds }
16451da177e4SLinus Torvalds 
acpi_ec_setup(struct acpi_ec * ec,struct acpi_device * device,bool call_reg)1646ab4620f5SHans de Goede static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool call_reg)
16471da177e4SLinus Torvalds {
164872c77b7eSLv Zheng 	int ret;
16491da177e4SLinus Torvalds 
165072c77b7eSLv Zheng 	/* First EC capable of handling transactions */
1651c823c17aSRafael J. Wysocki 	if (!first_ec)
165272c77b7eSLv Zheng 		first_ec = ec;
1653c823c17aSRafael J. Wysocki 
165496a0e06dSRafael J. Wysocki 	ret = ec_install_handlers(ec, device, call_reg);
165596a0e06dSRafael J. Wysocki 	if (ret) {
165696a0e06dSRafael J. Wysocki 		if (ec == first_ec)
165796a0e06dSRafael J. Wysocki 			first_ec = NULL;
165896a0e06dSRafael J. Wysocki 
165996a0e06dSRafael J. Wysocki 		return ret;
166096a0e06dSRafael J. Wysocki 	}
166196a0e06dSRafael J. Wysocki 
1662c823c17aSRafael J. Wysocki 	pr_info("EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->command_addr,
1663c823c17aSRafael J. Wysocki 		ec->data_addr);
1664c823c17aSRafael J. Wysocki 
1665c823c17aSRafael J. Wysocki 	if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
1666c823c17aSRafael J. Wysocki 		if (ec->gpe >= 0)
1667c823c17aSRafael J. Wysocki 			pr_info("GPE=0x%x\n", ec->gpe);
1668c823c17aSRafael J. Wysocki 		else
1669c823c17aSRafael J. Wysocki 			pr_info("IRQ=%d\n", ec->irq);
1670fd6231e7SLv Zheng 	}
167172c77b7eSLv Zheng 
167272c77b7eSLv Zheng 	return ret;
167372c77b7eSLv Zheng }
167472c77b7eSLv Zheng 
acpi_ec_add(struct acpi_device * device)1675fd6231e7SLv Zheng static int acpi_ec_add(struct acpi_device *device)
1676fd6231e7SLv Zheng {
1677e3cfabcdSRafael J. Wysocki 	struct acpi_ec *ec;
1678116f2b34SRafael J. Wysocki 	int ret;
1679fd6231e7SLv Zheng 
1680fd6231e7SLv Zheng 	strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
1681fd6231e7SLv Zheng 	strcpy(acpi_device_class(device), ACPI_EC_CLASS);
1682fd6231e7SLv Zheng 
1683d7e0481cSRafael J. Wysocki 	if (boot_ec && (boot_ec->handle == device->handle ||
1684d7e0481cSRafael J. Wysocki 	    !strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) {
1685e3cfabcdSRafael J. Wysocki 		/* Fast path: this device corresponds to the boot EC. */
1686a64a62ceSLv Zheng 		ec = boot_ec;
1687a64a62ceSLv Zheng 	} else {
1688e3cfabcdSRafael J. Wysocki 		acpi_status status;
1689e3cfabcdSRafael J. Wysocki 
1690fd6231e7SLv Zheng 		ec = acpi_ec_alloc();
16911da177e4SLinus Torvalds 		if (!ec)
16921da177e4SLinus Torvalds 			return -ENOMEM;
1693116f2b34SRafael J. Wysocki 
1694a64a62ceSLv Zheng 		status = ec_parse_device(device->handle, 0, ec, NULL);
1695a64a62ceSLv Zheng 		if (status != AE_CTRL_TERMINATE) {
169646922d2aSLv Zheng 			ret = -EINVAL;
169703e9a0e0SRafael J. Wysocki 			goto err;
16981da177e4SLinus Torvalds 		}
16991da177e4SLinus Torvalds 
1700116f2b34SRafael J. Wysocki 		if (boot_ec && ec->command_addr == boot_ec->command_addr &&
170181df5f91SHans de Goede 		    ec->data_addr == boot_ec->data_addr) {
170269b957c2SLv Zheng 			/*
170381df5f91SHans de Goede 			 * Trust PNP0C09 namespace location rather than ECDT ID.
170481df5f91SHans de Goede 			 * But trust ECDT GPE rather than _GPE because of ASUS
170581df5f91SHans de Goede 			 * quirks. So do not change boot_ec->gpe to ec->gpe,
170681df5f91SHans de Goede 			 * except when the TRUST_DSDT_GPE quirk is set.
170769b957c2SLv Zheng 			 */
170869b957c2SLv Zheng 			boot_ec->handle = ec->handle;
170981df5f91SHans de Goede 
171081df5f91SHans de Goede 			if (EC_FLAGS_TRUST_DSDT_GPE)
171181df5f91SHans de Goede 				boot_ec->gpe = ec->gpe;
171281df5f91SHans de Goede 
171397cb159fSLv Zheng 			acpi_handle_debug(ec->handle, "duplicated.\n");
171497cb159fSLv Zheng 			acpi_ec_free(ec);
171597cb159fSLv Zheng 			ec = boot_ec;
1716a64a62ceSLv Zheng 		}
1717d2c62aefSRafael J. Wysocki 	}
1718d2c62aefSRafael J. Wysocki 
1719ab4620f5SHans de Goede 	ret = acpi_ec_setup(ec, device, true);
172046922d2aSLv Zheng 	if (ret)
172103e9a0e0SRafael J. Wysocki 		goto err;
172246922d2aSLv Zheng 
1723d2c62aefSRafael J. Wysocki 	if (ec == boot_ec)
1724d2c62aefSRafael J. Wysocki 		acpi_handle_info(boot_ec->handle,
172565a691f5SRafael J. Wysocki 				 "Boot %s EC initialization complete\n",
1726116f2b34SRafael J. Wysocki 				 boot_ec_is_ecdt ? "ECDT" : "DSDT");
1727d2c62aefSRafael J. Wysocki 
172865a691f5SRafael J. Wysocki 	acpi_handle_info(ec->handle,
172965a691f5SRafael J. Wysocki 			 "EC: Used to handle transactions and events\n");
173065a691f5SRafael J. Wysocki 
17311da177e4SLinus Torvalds 	device->driver_data = ec;
1732de4f1046SThomas Renninger 
1733d6795fe3SAndi Kleen 	ret = !!request_region(ec->data_addr, 1, "EC data");
1734d6795fe3SAndi Kleen 	WARN(!ret, "Could not request EC data io port 0x%lx", ec->data_addr);
1735d6795fe3SAndi Kleen 	ret = !!request_region(ec->command_addr, 1, "EC cmd");
1736d6795fe3SAndi Kleen 	WARN(!ret, "Could not request EC cmd io port 0x%lx", ec->command_addr);
1737de4f1046SThomas Renninger 
17381c832b3eSLan Tianyu 	/* Reprobe devices depending on the EC */
1739a9e10e58SDaniel Scally 	acpi_dev_clear_dependencies(device);
1740e3cfabcdSRafael J. Wysocki 
174197cb159fSLv Zheng 	acpi_handle_debug(ec->handle, "enumerated.\n");
174246922d2aSLv Zheng 	return 0;
174346922d2aSLv Zheng 
174403e9a0e0SRafael J. Wysocki err:
174597cb159fSLv Zheng 	if (ec != boot_ec)
174646922d2aSLv Zheng 		acpi_ec_free(ec);
174703e9a0e0SRafael J. Wysocki 
1748837012edSAlexey Starikovskiy 	return ret;
17491da177e4SLinus Torvalds }
17501da177e4SLinus Torvalds 
acpi_ec_remove(struct acpi_device * device)17516c0eb5baSDawei Li static void acpi_ec_remove(struct acpi_device *device)
17521da177e4SLinus Torvalds {
1753c0900c35SAlexey Starikovskiy 	struct acpi_ec *ec;
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds 	if (!device)
17566c0eb5baSDawei Li 		return;
1757f9319f90SAlexey Starikovskiy 
17581da177e4SLinus Torvalds 	ec = acpi_driver_data(device);
1759de4f1046SThomas Renninger 	release_region(ec->data_addr, 1);
1760de4f1046SThomas Renninger 	release_region(ec->command_addr, 1);
17611da177e4SLinus Torvalds 	device->driver_data = NULL;
176297cb159fSLv Zheng 	if (ec != boot_ec) {
176397cb159fSLv Zheng 		ec_remove_handlers(ec);
176472c77b7eSLv Zheng 		acpi_ec_free(ec);
176597cb159fSLv Zheng 	}
17661da177e4SLinus Torvalds }
17671da177e4SLinus Torvalds 
acpi_ec_register_opregions(struct acpi_device * adev)1768d2c76802SRafael J. Wysocki void acpi_ec_register_opregions(struct acpi_device *adev)
1769d2c76802SRafael J. Wysocki {
1770d2c76802SRafael J. Wysocki 	if (first_ec && first_ec->handle != adev->handle)
1771d2c76802SRafael J. Wysocki 		acpi_execute_reg_methods(adev->handle, 1, ACPI_ADR_SPACE_EC);
1772d2c76802SRafael J. Wysocki }
1773d2c76802SRafael J. Wysocki 
17741da177e4SLinus Torvalds static acpi_status
ec_parse_io_ports(struct acpi_resource * resource,void * context)17751da177e4SLinus Torvalds ec_parse_io_ports(struct acpi_resource *resource, void *context)
17761da177e4SLinus Torvalds {
17771da177e4SLinus Torvalds 	struct acpi_ec *ec = context;
17781da177e4SLinus Torvalds 
17791da177e4SLinus Torvalds 	if (resource->type != ACPI_RESOURCE_TYPE_IO)
17801da177e4SLinus Torvalds 		return AE_OK;
17811da177e4SLinus Torvalds 
17821da177e4SLinus Torvalds 	/*
17831da177e4SLinus Torvalds 	 * The first address region returned is the data port, and
17841da177e4SLinus Torvalds 	 * the second address region returned is the status/command
17851da177e4SLinus Torvalds 	 * port.
17861da177e4SLinus Torvalds 	 */
1787de4f1046SThomas Renninger 	if (ec->data_addr == 0)
17881da177e4SLinus Torvalds 		ec->data_addr = resource->data.io.minimum;
1789de4f1046SThomas Renninger 	else if (ec->command_addr == 0)
17901da177e4SLinus Torvalds 		ec->command_addr = resource->data.io.minimum;
17911da177e4SLinus Torvalds 	else
17921da177e4SLinus Torvalds 		return AE_CTRL_TERMINATE;
17931da177e4SLinus Torvalds 
17941da177e4SLinus Torvalds 	return AE_OK;
17951da177e4SLinus Torvalds }
17961da177e4SLinus Torvalds 
1797dcf15cbdSLv Zheng static const struct acpi_device_id ec_device_ids[] = {
1798dcf15cbdSLv Zheng 	{"PNP0C09", 0},
1799a64a62ceSLv Zheng 	{ACPI_ECDT_HID, 0},
1800dcf15cbdSLv Zheng 	{"", 0},
1801dcf15cbdSLv Zheng };
1802dcf15cbdSLv Zheng 
1803c712bb58SLv Zheng /*
1804c712bb58SLv Zheng  * This function is not Windows-compatible as Windows never enumerates the
1805c712bb58SLv Zheng  * namespace EC before the main ACPI device enumeration process. It is
1806c712bb58SLv Zheng  * retained for historical reason and will be deprecated in the future.
1807c712bb58SLv Zheng  */
acpi_ec_dsdt_probe(void)1808fdb3c177SRafael J. Wysocki void __init acpi_ec_dsdt_probe(void)
1809c04209a7SAlexey Starikovskiy {
1810fd6231e7SLv Zheng 	struct acpi_ec *ec;
1811fdb3c177SRafael J. Wysocki 	acpi_status status;
1812fd6231e7SLv Zheng 	int ret;
1813dcf15cbdSLv Zheng 
1814c712bb58SLv Zheng 	/*
1815c712bb58SLv Zheng 	 * If a platform has ECDT, there is no need to proceed as the
1816c712bb58SLv Zheng 	 * following probe is not a part of the ACPI device enumeration,
1817c712bb58SLv Zheng 	 * executing _STA is not safe, and thus this probe may risk of
1818c712bb58SLv Zheng 	 * picking up an invalid EC device.
1819c712bb58SLv Zheng 	 */
1820c712bb58SLv Zheng 	if (boot_ec)
1821fdb3c177SRafael J. Wysocki 		return;
1822c712bb58SLv Zheng 
1823fd6231e7SLv Zheng 	ec = acpi_ec_alloc();
1824fd6231e7SLv Zheng 	if (!ec)
1825fdb3c177SRafael J. Wysocki 		return;
1826fdb3c177SRafael J. Wysocki 
1827dcf15cbdSLv Zheng 	/*
18282a570840SLv Zheng 	 * At this point, the namespace is initialized, so start to find
18292a570840SLv Zheng 	 * the namespace objects.
1830dcf15cbdSLv Zheng 	 */
1831fdb3c177SRafael J. Wysocki 	status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, ec, NULL);
1832fd6231e7SLv Zheng 	if (ACPI_FAILURE(status) || !ec->handle) {
1833fdb3c177SRafael J. Wysocki 		acpi_ec_free(ec);
1834fdb3c177SRafael J. Wysocki 		return;
1835c04209a7SAlexey Starikovskiy 	}
1836fdb3c177SRafael J. Wysocki 
18372a570840SLv Zheng 	/*
18382a570840SLv Zheng 	 * When the DSDT EC is available, always re-configure boot EC to
18392a570840SLv Zheng 	 * have _REG evaluated. _REG can only be evaluated after the
18402a570840SLv Zheng 	 * namespace initialization.
18412a570840SLv Zheng 	 * At this point, the GPE is not fully initialized, so do not to
18422a570840SLv Zheng 	 * handle the events.
18432a570840SLv Zheng 	 */
1844ab4620f5SHans de Goede 	ret = acpi_ec_setup(ec, NULL, true);
1845c746b6b6SRafael J. Wysocki 	if (ret) {
184672c77b7eSLv Zheng 		acpi_ec_free(ec);
1847c746b6b6SRafael J. Wysocki 		return;
1848c746b6b6SRafael J. Wysocki 	}
1849c746b6b6SRafael J. Wysocki 
1850c746b6b6SRafael J. Wysocki 	boot_ec = ec;
1851c746b6b6SRafael J. Wysocki 
1852c746b6b6SRafael J. Wysocki 	acpi_handle_info(ec->handle,
1853c746b6b6SRafael J. Wysocki 			 "Boot DSDT EC used to handle transactions\n");
1854c04209a7SAlexey Starikovskiy }
1855c04209a7SAlexey Starikovskiy 
18562a570840SLv Zheng /*
185798ada3c5SRafael J. Wysocki  * acpi_ec_ecdt_start - Finalize the boot ECDT EC initialization.
185869b957c2SLv Zheng  *
185998ada3c5SRafael J. Wysocki  * First, look for an ACPI handle for the boot ECDT EC if acpi_ec_add() has not
186098ada3c5SRafael J. Wysocki  * found a matching object in the namespace.
186198ada3c5SRafael J. Wysocki  *
186298ada3c5SRafael J. Wysocki  * Next, in case the DSDT EC is not functioning, it is still necessary to
186398ada3c5SRafael J. Wysocki  * provide a functional ECDT EC to handle events, so add an extra device object
186498ada3c5SRafael J. Wysocki  * to represent it (see https://bugzilla.kernel.org/show_bug.cgi?id=115021).
186598ada3c5SRafael J. Wysocki  *
186698ada3c5SRafael J. Wysocki  * This is useful on platforms with valid ECDT and invalid DSDT EC settings,
186798ada3c5SRafael J. Wysocki  * like ASUS X550ZE (see https://bugzilla.kernel.org/show_bug.cgi?id=196847).
18682a570840SLv Zheng  */
acpi_ec_ecdt_start(void)186998ada3c5SRafael J. Wysocki static void __init acpi_ec_ecdt_start(void)
187079149001SLv Zheng {
187198ada3c5SRafael J. Wysocki 	struct acpi_table_ecdt *ecdt_ptr;
187298ada3c5SRafael J. Wysocki 	acpi_handle handle;
187398ada3c5SRafael J. Wysocki 	acpi_status status;
1874ad332c8aSKieran Clancy 
187598ada3c5SRafael J. Wysocki 	/* Bail out if a matching EC has been found in the namespace. */
187698ada3c5SRafael J. Wysocki 	if (!boot_ec || boot_ec->handle != ACPI_ROOT_OBJECT)
187798ada3c5SRafael J. Wysocki 		return;
187898ada3c5SRafael J. Wysocki 
187998ada3c5SRafael J. Wysocki 	/* Look up the object pointed to from the ECDT in the namespace. */
188098ada3c5SRafael J. Wysocki 	status = acpi_get_table(ACPI_SIG_ECDT, 1,
188198ada3c5SRafael J. Wysocki 				(struct acpi_table_header **)&ecdt_ptr);
188298ada3c5SRafael J. Wysocki 	if (ACPI_FAILURE(status))
188398ada3c5SRafael J. Wysocki 		return;
188498ada3c5SRafael J. Wysocki 
188598ada3c5SRafael J. Wysocki 	status = acpi_get_handle(NULL, ecdt_ptr->id, &handle);
1886f900bf49SHanjun Guo 	if (ACPI_SUCCESS(status)) {
188798ada3c5SRafael J. Wysocki 		boot_ec->handle = handle;
188898ada3c5SRafael J. Wysocki 
188998ada3c5SRafael J. Wysocki 		/* Add a special ACPI device object to represent the boot EC. */
189098ada3c5SRafael J. Wysocki 		acpi_bus_register_early_device(ACPI_BUS_TYPE_ECDT_EC);
189167bfa9b6SFeng Tang 	}
189267bfa9b6SFeng Tang 
1893f900bf49SHanjun Guo 	acpi_put_table((struct acpi_table_header *)ecdt_ptr);
1894f900bf49SHanjun Guo }
1895f900bf49SHanjun Guo 
1896ad332c8aSKieran Clancy /*
1897b6a3e147SZhang Rui  * On some hardware it is necessary to clear events accumulated by the EC during
1898b6a3e147SZhang Rui  * sleep. These ECs stop reporting GPEs until they are manually polled, if too
1899b6a3e147SZhang Rui  * many events are accumulated. (e.g. Samsung Series 5/9 notebooks)
1900b6a3e147SZhang Rui  *
1901b6a3e147SZhang Rui  * https://bugzilla.kernel.org/show_bug.cgi?id=44161
1902b6a3e147SZhang Rui  *
1903b6a3e147SZhang Rui  * Ideally, the EC should also be instructed NOT to accumulate events during
1904b6a3e147SZhang Rui  * sleep (which Windows seems to do somehow), but the interface to control this
1905b6a3e147SZhang Rui  * behaviour is not known at this time.
1906b6a3e147SZhang Rui  *
1907b6a3e147SZhang Rui  * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx,
1908b6a3e147SZhang Rui  * however it is very likely that other Samsung models are affected.
1909b6a3e147SZhang Rui  *
1910b6a3e147SZhang Rui  * On systems which don't accumulate _Q events during sleep, this extra check
1911b6a3e147SZhang Rui  * should be harmless.
1912b6a3e147SZhang Rui  */
ec_clear_on_resume(const struct dmi_system_id * id)1913b6a3e147SZhang Rui static int ec_clear_on_resume(const struct dmi_system_id *id)
1914b6a3e147SZhang Rui {
1915b6a3e147SZhang Rui 	pr_debug("Detected system needing EC poll on resume.\n");
1916b6a3e147SZhang Rui 	EC_FLAGS_CLEAR_ON_RESUME = 1;
1917b6a3e147SZhang Rui 	ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
1918b6a3e147SZhang Rui 	return 0;
1919b6a3e147SZhang Rui }
1920b6a3e147SZhang Rui 
1921b6a3e147SZhang Rui /*
1922bc539567SLv Zheng  * Some ECDTs contain wrong register addresses.
1923bc539567SLv Zheng  * MSI MS-171F
1924bc539567SLv Zheng  * https://bugzilla.kernel.org/show_bug.cgi?id=12461
1925bc539567SLv Zheng  */
ec_correct_ecdt(const struct dmi_system_id * id)192659f0aa94SLv Zheng static int ec_correct_ecdt(const struct dmi_system_id *id)
192759f0aa94SLv Zheng {
192859f0aa94SLv Zheng 	pr_debug("Detected system needing ECDT address correction.\n");
192959f0aa94SLv Zheng 	EC_FLAGS_CORRECT_ECDT = 1;
193059f0aa94SLv Zheng 	return 0;
193159f0aa94SLv Zheng }
193259f0aa94SLv Zheng 
1933440f53daSChris Chiu /*
19344370cbf3SZhang Rui  * Some ECDTs contain wrong GPE setting, but they share the same port addresses
19354370cbf3SZhang Rui  * with DSDT EC, don't duplicate the DSDT EC with ECDT EC in this case.
19364370cbf3SZhang Rui  * https://bugzilla.kernel.org/show_bug.cgi?id=209989
19374370cbf3SZhang Rui  */
ec_honor_dsdt_gpe(const struct dmi_system_id * id)19384370cbf3SZhang Rui static int ec_honor_dsdt_gpe(const struct dmi_system_id *id)
19394370cbf3SZhang Rui {
19404370cbf3SZhang Rui 	pr_debug("Detected system needing DSDT GPE setting.\n");
19414370cbf3SZhang Rui 	EC_FLAGS_TRUST_DSDT_GPE = 1;
19424370cbf3SZhang Rui 	return 0;
19434370cbf3SZhang Rui }
19444370cbf3SZhang Rui 
19456faadbbbSChristoph Hellwig static const struct dmi_system_id ec_dmi_table[] __initconst = {
19460adf3c74SAlexey Starikovskiy 	{
19473e6573c5SHans de Goede 		/*
19483e6573c5SHans de Goede 		 * MSI MS-171F
19493e6573c5SHans de Goede 		 * https://bugzilla.kernel.org/show_bug.cgi?id=12461
19503e6573c5SHans de Goede 		 */
19513e6573c5SHans de Goede 		.callback = ec_correct_ecdt,
19523e6573c5SHans de Goede 		.matches = {
19533174abcfSLv Zheng 			DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
19543e6573c5SHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),
19553e6573c5SHans de Goede 		},
19563e6573c5SHans de Goede 	},
1957440f53daSChris Chiu 	{
19583e6573c5SHans de Goede 		/*
19593e6573c5SHans de Goede 		 * HP Pavilion Gaming Laptop 15-cx0xxx
19603e6573c5SHans de Goede 		 * https://bugzilla.kernel.org/show_bug.cgi?id=209989
19613e6573c5SHans de Goede 		 */
19623e6573c5SHans de Goede 		.callback = ec_honor_dsdt_gpe,
19633e6573c5SHans de Goede 		.matches = {
19644370cbf3SZhang Rui 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
19653e6573c5SHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-cx0xxx"),
19663e6573c5SHans de Goede 		},
19673e6573c5SHans de Goede 	},
19684370cbf3SZhang Rui 	{
19693e6573c5SHans de Goede 		/*
1970b423f240SMia Kanashi 		 * HP Pavilion Gaming Laptop 15-cx0041ur
1971b423f240SMia Kanashi 		 */
1972b423f240SMia Kanashi 		.callback = ec_honor_dsdt_gpe,
1973b423f240SMia Kanashi 		.matches = {
1974b423f240SMia Kanashi 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
1975b423f240SMia Kanashi 			DMI_MATCH(DMI_PRODUCT_NAME, "HP 15-cx0041ur"),
1976b423f240SMia Kanashi 		},
1977b423f240SMia Kanashi 	},
1978b423f240SMia Kanashi 	{
1979b423f240SMia Kanashi 		/*
1980cd4aece4SHans de Goede 		 * HP Pavilion Gaming Laptop 15-dk1xxx
1981cd4aece4SHans de Goede 		 * https://github.com/systemd/systemd/issues/28942
1982cd4aece4SHans de Goede 		 */
1983cd4aece4SHans de Goede 		.callback = ec_honor_dsdt_gpe,
1984cd4aece4SHans de Goede 		.matches = {
1985cd4aece4SHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
1986cd4aece4SHans de Goede 			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion Gaming Laptop 15-dk1xxx"),
1987cd4aece4SHans de Goede 		},
1988cd4aece4SHans de Goede 	},
1989cd4aece4SHans de Goede 	{
1990cd4aece4SHans de Goede 		/*
19912deacc5cSJonathan Denose 		 * HP 250 G7 Notebook PC
19922deacc5cSJonathan Denose 		 */
19932deacc5cSJonathan Denose 		.callback = ec_honor_dsdt_gpe,
19942deacc5cSJonathan Denose 		.matches = {
19952deacc5cSJonathan Denose 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
19962deacc5cSJonathan Denose 			DMI_MATCH(DMI_PRODUCT_NAME, "HP 250 G7 Notebook PC"),
19972deacc5cSJonathan Denose 		},
19982deacc5cSJonathan Denose 	},
19992deacc5cSJonathan Denose 	{
20002deacc5cSJonathan Denose 		/*
20013e6573c5SHans de Goede 		 * Samsung hardware
20023e6573c5SHans de Goede 		 * https://bugzilla.kernel.org/show_bug.cgi?id=44161
20033e6573c5SHans de Goede 		 */
20043e6573c5SHans de Goede 		.callback = ec_clear_on_resume,
20053e6573c5SHans de Goede 		.matches = {
20063e6573c5SHans de Goede 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
20073e6573c5SHans de Goede 		},
20083e6573c5SHans de Goede 	},
20093e6573c5SHans de Goede 	{}
20100adf3c74SAlexey Starikovskiy };
20110adf3c74SAlexey Starikovskiy 
acpi_ec_ecdt_probe(void)2012fdb3c177SRafael J. Wysocki void __init acpi_ec_ecdt_probe(void)
20131da177e4SLinus Torvalds {
2014c0900c35SAlexey Starikovskiy 	struct acpi_table_ecdt *ecdt_ptr;
2015fd6231e7SLv Zheng 	struct acpi_ec *ec;
2016fdb3c177SRafael J. Wysocki 	acpi_status status;
2017fdb3c177SRafael J. Wysocki 	int ret;
20181da177e4SLinus Torvalds 
2019fdb3c177SRafael J. Wysocki 	/* Generate a boot ec context. */
20200adf3c74SAlexey Starikovskiy 	dmi_check_system(ec_dmi_table);
2021c0900c35SAlexey Starikovskiy 	status = acpi_get_table(ACPI_SIG_ECDT, 1,
2022c0900c35SAlexey Starikovskiy 				(struct acpi_table_header **)&ecdt_ptr);
2023fdb3c177SRafael J. Wysocki 	if (ACPI_FAILURE(status))
2024fdb3c177SRafael J. Wysocki 		return;
202559f0aa94SLv Zheng 
202659f0aa94SLv Zheng 	if (!ecdt_ptr->control.address || !ecdt_ptr->data.address) {
202759f0aa94SLv Zheng 		/*
202859f0aa94SLv Zheng 		 * Asus X50GL:
202959f0aa94SLv Zheng 		 * https://bugzilla.kernel.org/show_bug.cgi?id=11880
203059f0aa94SLv Zheng 		 */
2031f900bf49SHanjun Guo 		goto out;
203259f0aa94SLv Zheng 	}
203359f0aa94SLv Zheng 
2034fdb3c177SRafael J. Wysocki 	ec = acpi_ec_alloc();
2035fdb3c177SRafael J. Wysocki 	if (!ec)
2036f900bf49SHanjun Guo 		goto out;
2037fdb3c177SRafael J. Wysocki 
203859f0aa94SLv Zheng 	if (EC_FLAGS_CORRECT_ECDT) {
2039fd6231e7SLv Zheng 		ec->command_addr = ecdt_ptr->data.address;
2040fd6231e7SLv Zheng 		ec->data_addr = ecdt_ptr->control.address;
204159f0aa94SLv Zheng 	} else {
2042fd6231e7SLv Zheng 		ec->command_addr = ecdt_ptr->control.address;
2043fd6231e7SLv Zheng 		ec->data_addr = ecdt_ptr->data.address;
204459f0aa94SLv Zheng 	}
2045406857f7SDaniel Drake 
2046406857f7SDaniel Drake 	/*
2047406857f7SDaniel Drake 	 * Ignore the GPE value on Reduced Hardware platforms.
2048406857f7SDaniel Drake 	 * Some products have this set to an erroneous value.
2049406857f7SDaniel Drake 	 */
2050406857f7SDaniel Drake 	if (!acpi_gbl_reduced_hardware)
2051fd6231e7SLv Zheng 		ec->gpe = ecdt_ptr->gpe;
2052406857f7SDaniel Drake 
20531568426cSRafael J. Wysocki 	ec->handle = ACPI_ROOT_OBJECT;
20542a570840SLv Zheng 
20552a570840SLv Zheng 	/*
20562a570840SLv Zheng 	 * At this point, the namespace is not initialized, so do not find
20572a570840SLv Zheng 	 * the namespace objects, or handle the events.
20582a570840SLv Zheng 	 */
2059ab4620f5SHans de Goede 	ret = acpi_ec_setup(ec, NULL, false);
20601568426cSRafael J. Wysocki 	if (ret) {
206172c77b7eSLv Zheng 		acpi_ec_free(ec);
2062f900bf49SHanjun Guo 		goto out;
20631568426cSRafael J. Wysocki 	}
20641568426cSRafael J. Wysocki 
20651568426cSRafael J. Wysocki 	boot_ec = ec;
20661568426cSRafael J. Wysocki 	boot_ec_is_ecdt = true;
20671568426cSRafael J. Wysocki 
20681568426cSRafael J. Wysocki 	pr_info("Boot ECDT EC used to handle transactions\n");
2069f900bf49SHanjun Guo 
2070f900bf49SHanjun Guo out:
2071f900bf49SHanjun Guo 	acpi_put_table((struct acpi_table_header *)ecdt_ptr);
20721da177e4SLinus Torvalds }
20731da177e4SLinus Torvalds 
2074df45db61SLv Zheng #ifdef CONFIG_PM_SLEEP
acpi_ec_suspend(struct device * dev)207539a2a2aaSLv Zheng static int acpi_ec_suspend(struct device *dev)
207639a2a2aaSLv Zheng {
207739a2a2aaSLv Zheng 	struct acpi_ec *ec =
207839a2a2aaSLv Zheng 		acpi_driver_data(to_acpi_device(dev));
207939a2a2aaSLv Zheng 
20806e86633aSRafael J. Wysocki 	if (!pm_suspend_no_platform() && ec_freeze_events)
208139a2a2aaSLv Zheng 		acpi_ec_disable_event(ec);
208239a2a2aaSLv Zheng 	return 0;
208339a2a2aaSLv Zheng }
208439a2a2aaSLv Zheng 
acpi_ec_suspend_noirq(struct device * dev)208576380636SRafael J. Wysocki static int acpi_ec_suspend_noirq(struct device *dev)
208676380636SRafael J. Wysocki {
208776380636SRafael J. Wysocki 	struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
208876380636SRafael J. Wysocki 
208976380636SRafael J. Wysocki 	/*
209076380636SRafael J. Wysocki 	 * The SCI handler doesn't run at this point, so the GPE can be
209176380636SRafael J. Wysocki 	 * masked at the low level without side effects.
209276380636SRafael J. Wysocki 	 */
209376380636SRafael J. Wysocki 	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
2094406857f7SDaniel Drake 	    ec->gpe >= 0 && ec->reference_count >= 1)
209576380636SRafael J. Wysocki 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
209676380636SRafael J. Wysocki 
20973cd091a7SRafael J. Wysocki 	acpi_ec_enter_noirq(ec);
20983cd091a7SRafael J. Wysocki 
209976380636SRafael J. Wysocki 	return 0;
210076380636SRafael J. Wysocki }
210176380636SRafael J. Wysocki 
acpi_ec_resume_noirq(struct device * dev)210276380636SRafael J. Wysocki static int acpi_ec_resume_noirq(struct device *dev)
210376380636SRafael J. Wysocki {
210476380636SRafael J. Wysocki 	struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
210576380636SRafael J. Wysocki 
21063cd091a7SRafael J. Wysocki 	acpi_ec_leave_noirq(ec);
21073cd091a7SRafael J. Wysocki 
210876380636SRafael J. Wysocki 	if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
2109406857f7SDaniel Drake 	    ec->gpe >= 0 && ec->reference_count >= 1)
211076380636SRafael J. Wysocki 		acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
211176380636SRafael J. Wysocki 
211276380636SRafael J. Wysocki 	return 0;
211376380636SRafael J. Wysocki }
211476380636SRafael J. Wysocki 
acpi_ec_resume(struct device * dev)2115c2b46d67SLv Zheng static int acpi_ec_resume(struct device *dev)
2116c2b46d67SLv Zheng {
2117c2b46d67SLv Zheng 	struct acpi_ec *ec =
2118c2b46d67SLv Zheng 		acpi_driver_data(to_acpi_device(dev));
2119c2b46d67SLv Zheng 
2120c2b46d67SLv Zheng 	acpi_ec_enable_event(ec);
2121c2b46d67SLv Zheng 	return 0;
2122c2b46d67SLv Zheng }
2123d7589404SRafael J. Wysocki 
acpi_ec_mark_gpe_for_wake(void)2124d7589404SRafael J. Wysocki void acpi_ec_mark_gpe_for_wake(void)
2125d7589404SRafael J. Wysocki {
2126d7589404SRafael J. Wysocki 	if (first_ec && !ec_no_wakeup)
2127d7589404SRafael J. Wysocki 		acpi_mark_gpe_for_wake(NULL, first_ec->gpe);
2128d7589404SRafael J. Wysocki }
2129d7589404SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_ec_mark_gpe_for_wake);
2130d7589404SRafael J. Wysocki 
acpi_ec_set_gpe_wake_mask(u8 action)2131d7589404SRafael J. Wysocki void acpi_ec_set_gpe_wake_mask(u8 action)
2132d7589404SRafael J. Wysocki {
2133d7589404SRafael J. Wysocki 	if (pm_suspend_no_platform() && first_ec && !ec_no_wakeup)
2134d7589404SRafael J. Wysocki 		acpi_set_gpe_wake_mask(NULL, first_ec->gpe, action);
2135d7589404SRafael J. Wysocki }
2136d7589404SRafael J. Wysocki 
acpi_ec_work_in_progress(struct acpi_ec * ec)21379aa60f3cSRafael J. Wysocki static bool acpi_ec_work_in_progress(struct acpi_ec *ec)
21389aa60f3cSRafael J. Wysocki {
21399aa60f3cSRafael J. Wysocki 	return ec->events_in_progress + ec->queries_in_progress > 0;
21409aa60f3cSRafael J. Wysocki }
21419aa60f3cSRafael J. Wysocki 
acpi_ec_dispatch_gpe(void)2142d7589404SRafael J. Wysocki bool acpi_ec_dispatch_gpe(void)
2143d7589404SRafael J. Wysocki {
2144ca8283dcSRafael J. Wysocki 	bool work_in_progress = false;
2145d7589404SRafael J. Wysocki 
2146d7589404SRafael J. Wysocki 	if (!first_ec)
21477b301750SRafael J. Wysocki 		return acpi_any_gpe_status_set(U32_MAX);
21487b301750SRafael J. Wysocki 
21497b301750SRafael J. Wysocki 	/*
21507b301750SRafael J. Wysocki 	 * Report wakeup if the status bit is set for any enabled GPE other
21517b301750SRafael J. Wysocki 	 * than the EC one.
21527b301750SRafael J. Wysocki 	 */
21537b301750SRafael J. Wysocki 	if (acpi_any_gpe_status_set(first_ec->gpe))
21547b301750SRafael J. Wysocki 		return true;
21557b301750SRafael J. Wysocki 
21567b301750SRafael J. Wysocki 	/*
2157dc0075baSRafael J. Wysocki 	 * Cancel the SCI wakeup and process all pending events in case there
2158dc0075baSRafael J. Wysocki 	 * are any wakeup ones in there.
2159dc0075baSRafael J. Wysocki 	 *
2160dc0075baSRafael J. Wysocki 	 * Note that if any non-EC GPEs are active at this point, the SCI will
2161dc0075baSRafael J. Wysocki 	 * retrigger after the rearming in acpi_s2idle_wake(), so no events
2162dc0075baSRafael J. Wysocki 	 * should be missed by canceling the wakeup here.
2163dc0075baSRafael J. Wysocki 	 */
2164dc0075baSRafael J. Wysocki 	pm_system_cancel_wakeup();
2165dc0075baSRafael J. Wysocki 
2166dc0075baSRafael J. Wysocki 	/*
21677b301750SRafael J. Wysocki 	 * Dispatch the EC GPE in-band, but do not report wakeup in any case
21687b301750SRafael J. Wysocki 	 * to allow the caller to process events properly after that.
21697b301750SRafael J. Wysocki 	 */
2170ca8283dcSRafael J. Wysocki 	spin_lock_irq(&first_ec->lock);
2171ca8283dcSRafael J. Wysocki 
2172977dc308SRafael J. Wysocki 	if (acpi_ec_gpe_status_set(first_ec)) {
2173977dc308SRafael J. Wysocki 		pm_pr_dbg("ACPI EC GPE status set\n");
2174977dc308SRafael J. Wysocki 
2175b5539eb5SRafael J. Wysocki 		clear_gpe_and_advance_transaction(first_ec, false);
21769aa60f3cSRafael J. Wysocki 		work_in_progress = acpi_ec_work_in_progress(first_ec);
2177977dc308SRafael J. Wysocki 	}
2178ca8283dcSRafael J. Wysocki 
2179ca8283dcSRafael J. Wysocki 	spin_unlock_irq(&first_ec->lock);
2180ca8283dcSRafael J. Wysocki 
2181ca8283dcSRafael J. Wysocki 	if (!work_in_progress)
2182ca8283dcSRafael J. Wysocki 		return false;
2183ca8283dcSRafael J. Wysocki 
21845fcd7359SRafael J. Wysocki 	pm_pr_dbg("ACPI EC GPE dispatched\n");
21857b301750SRafael J. Wysocki 
21864a9af6caSRafael J. Wysocki 	/* Drain EC work. */
21874a9af6caSRafael J. Wysocki 	do {
2188607b9df6SRafael J. Wysocki 		acpi_ec_flush_work();
2189607b9df6SRafael J. Wysocki 
21904a9af6caSRafael J. Wysocki 		pm_pr_dbg("ACPI EC work flushed\n");
21914a9af6caSRafael J. Wysocki 
21924a9af6caSRafael J. Wysocki 		spin_lock_irq(&first_ec->lock);
21934a9af6caSRafael J. Wysocki 
21949aa60f3cSRafael J. Wysocki 		work_in_progress = acpi_ec_work_in_progress(first_ec);
21954a9af6caSRafael J. Wysocki 
21964a9af6caSRafael J. Wysocki 		spin_unlock_irq(&first_ec->lock);
21974a9af6caSRafael J. Wysocki 	} while (work_in_progress && !pm_wakeup_pending());
21984a9af6caSRafael J. Wysocki 
219929113f2fSRafael J. Wysocki 	return false;
2200d7589404SRafael J. Wysocki }
2201d7589404SRafael J. Wysocki #endif /* CONFIG_PM_SLEEP */
2202df45db61SLv Zheng 
2203df45db61SLv Zheng static const struct dev_pm_ops acpi_ec_pm = {
220476380636SRafael J. Wysocki 	SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend_noirq, acpi_ec_resume_noirq)
220539a2a2aaSLv Zheng 	SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume)
2206df45db61SLv Zheng };
2207df45db61SLv Zheng 
param_set_event_clearing(const char * val,const struct kernel_param * kp)2208e4dca7b7SKees Cook static int param_set_event_clearing(const char *val,
2209e4dca7b7SKees Cook 				    const struct kernel_param *kp)
22101d68d261SLv Zheng {
22111d68d261SLv Zheng 	int result = 0;
22121d68d261SLv Zheng 
22131d68d261SLv Zheng 	if (!strncmp(val, "status", sizeof("status") - 1)) {
22141d68d261SLv Zheng 		ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
22151d68d261SLv Zheng 		pr_info("Assuming SCI_EVT clearing on EC_SC accesses\n");
22161d68d261SLv Zheng 	} else if (!strncmp(val, "query", sizeof("query") - 1)) {
22171d68d261SLv Zheng 		ec_event_clearing = ACPI_EC_EVT_TIMING_QUERY;
22181d68d261SLv Zheng 		pr_info("Assuming SCI_EVT clearing on QR_EC writes\n");
22191d68d261SLv Zheng 	} else if (!strncmp(val, "event", sizeof("event") - 1)) {
22201d68d261SLv Zheng 		ec_event_clearing = ACPI_EC_EVT_TIMING_EVENT;
22211d68d261SLv Zheng 		pr_info("Assuming SCI_EVT clearing on event reads\n");
22221d68d261SLv Zheng 	} else
22231d68d261SLv Zheng 		result = -EINVAL;
22241d68d261SLv Zheng 	return result;
22251d68d261SLv Zheng }
22261d68d261SLv Zheng 
param_get_event_clearing(char * buffer,const struct kernel_param * kp)2227e4dca7b7SKees Cook static int param_get_event_clearing(char *buffer,
2228e4dca7b7SKees Cook 				    const struct kernel_param *kp)
22291d68d261SLv Zheng {
22301d68d261SLv Zheng 	switch (ec_event_clearing) {
22311d68d261SLv Zheng 	case ACPI_EC_EVT_TIMING_STATUS:
2232fc293b7aSXiongfeng Wang 		return sprintf(buffer, "status\n");
22331d68d261SLv Zheng 	case ACPI_EC_EVT_TIMING_QUERY:
2234fc293b7aSXiongfeng Wang 		return sprintf(buffer, "query\n");
22351d68d261SLv Zheng 	case ACPI_EC_EVT_TIMING_EVENT:
2236fc293b7aSXiongfeng Wang 		return sprintf(buffer, "event\n");
22371d68d261SLv Zheng 	default:
2238fc293b7aSXiongfeng Wang 		return sprintf(buffer, "invalid\n");
22391d68d261SLv Zheng 	}
22401d68d261SLv Zheng 	return 0;
22411d68d261SLv Zheng }
22421d68d261SLv Zheng 
22431d68d261SLv Zheng module_param_call(ec_event_clearing, param_set_event_clearing, param_get_event_clearing,
22441d68d261SLv Zheng 		  NULL, 0644);
22451d68d261SLv Zheng MODULE_PARM_DESC(ec_event_clearing, "Assumed SCI_EVT clearing timing");
22461d68d261SLv Zheng 
2247223883b7SAlexey Starikovskiy static struct acpi_driver acpi_ec_driver = {
2248223883b7SAlexey Starikovskiy 	.name = "ec",
2249223883b7SAlexey Starikovskiy 	.class = ACPI_EC_CLASS,
2250223883b7SAlexey Starikovskiy 	.ids = ec_device_ids,
2251223883b7SAlexey Starikovskiy 	.ops = {
2252223883b7SAlexey Starikovskiy 		.add = acpi_ec_add,
2253223883b7SAlexey Starikovskiy 		.remove = acpi_ec_remove,
2254223883b7SAlexey Starikovskiy 		},
2255df45db61SLv Zheng 	.drv.pm = &acpi_ec_pm,
2256223883b7SAlexey Starikovskiy };
2257223883b7SAlexey Starikovskiy 
acpi_ec_destroy_workqueues(void)2258f0ac20c3SRafael J. Wysocki static void acpi_ec_destroy_workqueues(void)
2259e1191bd4SLv Zheng {
2260f0ac20c3SRafael J. Wysocki 	if (ec_wq) {
2261f0ac20c3SRafael J. Wysocki 		destroy_workqueue(ec_wq);
2262f0ac20c3SRafael J. Wysocki 		ec_wq = NULL;
2263e1191bd4SLv Zheng 	}
2264e1191bd4SLv Zheng 	if (ec_query_wq) {
2265e1191bd4SLv Zheng 		destroy_workqueue(ec_query_wq);
2266e1191bd4SLv Zheng 		ec_query_wq = NULL;
2267e1191bd4SLv Zheng 	}
2268e1191bd4SLv Zheng }
2269e1191bd4SLv Zheng 
acpi_ec_init_workqueues(void)2270f0ac20c3SRafael J. Wysocki static int acpi_ec_init_workqueues(void)
2271f0ac20c3SRafael J. Wysocki {
2272f0ac20c3SRafael J. Wysocki 	if (!ec_wq)
2273f0ac20c3SRafael J. Wysocki 		ec_wq = alloc_ordered_workqueue("kec", 0);
2274f0ac20c3SRafael J. Wysocki 
2275f0ac20c3SRafael J. Wysocki 	if (!ec_query_wq)
2276f0ac20c3SRafael J. Wysocki 		ec_query_wq = alloc_workqueue("kec_query", 0, ec_max_queries);
2277f0ac20c3SRafael J. Wysocki 
2278f0ac20c3SRafael J. Wysocki 	if (!ec_wq || !ec_query_wq) {
2279f0ac20c3SRafael J. Wysocki 		acpi_ec_destroy_workqueues();
2280f0ac20c3SRafael J. Wysocki 		return -ENODEV;
2281f0ac20c3SRafael J. Wysocki 	}
2282f0ac20c3SRafael J. Wysocki 	return 0;
2283f0ac20c3SRafael J. Wysocki }
2284f0ac20c3SRafael J. Wysocki 
22858195a655SMika Westerberg static const struct dmi_system_id acpi_ec_no_wakeup[] = {
22868195a655SMika Westerberg 	{
22878195a655SMika Westerberg 		.matches = {
22888195a655SMika Westerberg 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
22892c4d6bafSRobin H. Johnson 			DMI_MATCH(DMI_PRODUCT_FAMILY, "Thinkpad X1 Carbon 6th"),
22908195a655SMika Westerberg 		},
22918195a655SMika Westerberg 	},
2292b047c62eSAaron Ma 	{
2293b047c62eSAaron Ma 		.matches = {
2294b047c62eSAaron Ma 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
2295b047c62eSAaron Ma 			DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Yoga 3rd"),
2296b047c62eSAaron Ma 		},
2297b047c62eSAaron Ma 	},
2298eb794e3cSBinbin Zhou 	{
2299eb794e3cSBinbin Zhou 		.matches = {
2300eb794e3cSBinbin Zhou 			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
2301eb794e3cSBinbin Zhou 			DMI_MATCH(DMI_PRODUCT_FAMILY, "103C_5336AN HP ZHAN 66 Pro"),
2302eb794e3cSBinbin Zhou 		},
2303eb794e3cSBinbin Zhou 	},
23048195a655SMika Westerberg 	{ },
23058195a655SMika Westerberg };
23068195a655SMika Westerberg 
acpi_ec_init(void)230798ada3c5SRafael J. Wysocki void __init acpi_ec_init(void)
23081da177e4SLinus Torvalds {
2309e1191bd4SLv Zheng 	int result;
23101da177e4SLinus Torvalds 
2311f0ac20c3SRafael J. Wysocki 	result = acpi_ec_init_workqueues();
2312e1191bd4SLv Zheng 	if (result)
231398ada3c5SRafael J. Wysocki 		return;
231498529b92SLv Zheng 
23158195a655SMika Westerberg 	/*
23168195a655SMika Westerberg 	 * Disable EC wakeup on following systems to prevent periodic
23178195a655SMika Westerberg 	 * wakeup from EC GPE.
23188195a655SMika Westerberg 	 */
23198195a655SMika Westerberg 	if (dmi_check_system(acpi_ec_no_wakeup)) {
23208195a655SMika Westerberg 		ec_no_wakeup = true;
23218195a655SMika Westerberg 		pr_debug("Disabling EC wakeup on suspend-to-idle\n");
23228195a655SMika Westerberg 	}
23238195a655SMika Westerberg 
232498ada3c5SRafael J. Wysocki 	/* Driver must be registered after acpi_ec_init_workqueues(). */
232598ada3c5SRafael J. Wysocki 	acpi_bus_register_driver(&acpi_ec_driver);
232698ada3c5SRafael J. Wysocki 
232798ada3c5SRafael J. Wysocki 	acpi_ec_ecdt_start();
23281da177e4SLinus Torvalds }
23291da177e4SLinus Torvalds 
23301da177e4SLinus Torvalds /* EC driver currently not unloadable */
23311da177e4SLinus Torvalds #if 0
233250526df6SLen Brown static void __exit acpi_ec_exit(void)
23331da177e4SLinus Torvalds {
23341da177e4SLinus Torvalds 
23351da177e4SLinus Torvalds 	acpi_bus_unregister_driver(&acpi_ec_driver);
2336f0ac20c3SRafael J. Wysocki 	acpi_ec_destroy_workqueues();
23371da177e4SLinus Torvalds }
23381da177e4SLinus Torvalds #endif	/* 0 */
2339