2019-05-29 07:17:56 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2013-02-25 14:08:37 -08:00
/*
* ChromeOS EC multi - function device
*
* Copyright ( C ) 2012 Google , Inc
*
* The ChromeOS EC multi function device is used to mux all the requests
* to the EC device for its multiple features : keyboard controller ,
* battery charging and regulator control , firmware update .
*/
# include <linux/interrupt.h>
2013-03-20 09:46:15 +01:00
# include <linux/module.h>
2022-02-16 16:03:05 +08:00
# include <linux/of_platform.h>
2023-07-14 11:49:09 -06:00
# include <linux/platform_device.h>
2019-09-02 11:53:05 +02:00
# include <linux/platform_data/cros_ec_commands.h>
# include <linux/platform_data/cros_ec_proto.h>
2022-02-16 16:03:05 +08:00
# include <linux/slab.h>
2016-12-16 18:57:37 +01:00
# include <linux/suspend.h>
2014-09-18 17:18:56 +02:00
platform/chrome: cros_ec: Match implementation with headers
The 'cros_ec' core driver is the common interface for the cros_ec
transport drivers to do the shared operations to register, unregister,
suspend, resume and handle_event. The interface is provided by including
the header 'include/linux/platform_data/cros_ec_proto.h', however, instead
of have the implementation of these functions in cros_ec_proto.c, it is in
'cros_ec.c', which is a different kernel module. Apart from being a bad
practice, this can induce confusions allowing the users of the cros_ec
protocol to call these functions.
The register, unregister, suspend, resume and handle_event functions
*should* only be called by the different transport drivers (i2c, spi, lpc,
etc.), so make this a bit less confusing by moving these functions from
the public in-kernel space to a private include in platform/chrome, and
then, the interface for cros_ec module and for the cros_ec_proto module is
clean.
Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
Signed-off-by: Benson Leung <bleung@chromium.org>
2020-01-22 10:07:01 +01:00
# include "cros_ec.h"
2015-06-15 21:39:39 +08:00
static struct cros_ec_platform ec_p = {
2015-06-09 13:04:47 +02:00
. ec_name = CROS_EC_DEV_NAME ,
. cmd_offset = EC_CMD_PASSTHRU_OFFSET ( CROS_EC_DEV_EC_INDEX ) ,
} ;
2015-06-15 21:39:39 +08:00
static struct cros_ec_platform pd_p = {
2015-06-09 13:04:47 +02:00
. ec_name = CROS_EC_DEV_PD_NAME ,
. cmd_offset = EC_CMD_PASSTHRU_OFFSET ( CROS_EC_DEV_PD_INDEX ) ,
} ;
2021-01-21 21:46:36 -08:00
/**
* cros_ec_irq_handler ( ) - top half part of the interrupt handler
* @ irq : IRQ id
* @ data : ( ec_dev ) Device with events to process .
*
* Return : Wakeup the bottom half
*/
static irqreturn_t cros_ec_irq_handler ( int irq , void * data )
2019-11-19 13:45:46 +01:00
{
struct cros_ec_device * ec_dev = data ;
ec_dev - > last_event_time = cros_ec_get_time_ns ( ) ;
return IRQ_WAKE_THREAD ;
}
2019-11-19 13:45:46 +01:00
/**
* cros_ec_handle_event ( ) - process and forward pending events on EC
* @ ec_dev : Device with events to process .
*
* Call this function in a loop when the kernel is notified that the EC has
* pending events .
*
* Return : true if more events are still pending and this function should be
* called again .
*/
2021-01-21 21:46:36 -08:00
static bool cros_ec_handle_event ( struct cros_ec_device * ec_dev )
2016-08-10 19:05:24 +02:00
{
2019-11-19 13:45:46 +01:00
bool wake_event ;
bool ec_has_more_events ;
2016-08-10 19:05:24 +02:00
int ret ;
2019-11-19 13:45:46 +01:00
ret = cros_ec_get_next_event ( ec_dev , & wake_event , & ec_has_more_events ) ;
2017-02-14 20:58:02 +01:00
/*
* Signal only if wake host events or any interrupt if
* cros_ec_get_next_event ( ) returned an error ( default value for
* wake_event is true )
*/
if ( wake_event & & device_may_wakeup ( ec_dev - > dev ) )
2016-08-10 19:05:24 +02:00
pm_wakeup_event ( ec_dev - > dev , 0 ) ;
if ( ret > 0 )
blocking_notifier_call_chain ( & ec_dev - > event_notifier ,
0 , ec_dev ) ;
2019-11-19 13:45:46 +01:00
return ec_has_more_events ;
}
2021-01-21 21:46:36 -08:00
/**
* cros_ec_irq_thread ( ) - bottom half part of the interrupt handler
* @ irq : IRQ id
* @ data : ( ec_dev ) Device with events to process .
*
* Return : Interrupt handled .
*/
irqreturn_t cros_ec_irq_thread ( int irq , void * data )
2019-11-19 13:45:46 +01:00
{
struct cros_ec_device * ec_dev = data ;
bool ec_has_more_events ;
do {
ec_has_more_events = cros_ec_handle_event ( ec_dev ) ;
} while ( ec_has_more_events ) ;
2016-08-10 19:05:24 +02:00
return IRQ_HANDLED ;
}
2021-01-21 21:46:36 -08:00
EXPORT_SYMBOL ( cros_ec_irq_thread ) ;
2016-08-10 19:05:24 +02:00
2016-12-16 18:57:37 +01:00
static int cros_ec_sleep_event ( struct cros_ec_device * ec_dev , u8 sleep_event )
{
2019-04-03 14:34:28 -07:00
int ret ;
2016-12-16 18:57:37 +01:00
struct {
struct cros_ec_command msg ;
2019-04-03 14:34:28 -07:00
union {
struct ec_params_host_sleep_event req0 ;
struct ec_params_host_sleep_event_v1 req1 ;
struct ec_response_host_sleep_event_v1 resp1 ;
} u ;
2016-12-16 18:57:37 +01:00
} __packed buf ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
2019-04-03 14:34:28 -07:00
if ( ec_dev - > host_sleep_v1 ) {
buf . u . req1 . sleep_event = sleep_event ;
buf . u . req1 . suspend_params . sleep_timeout_ms =
2022-08-22 14:40:40 -07:00
ec_dev - > suspend_timeout_ms ;
2019-04-03 14:34:28 -07:00
buf . msg . outsize = sizeof ( buf . u . req1 ) ;
if ( ( sleep_event = = HOST_SLEEP_EVENT_S3_RESUME ) | |
( sleep_event = = HOST_SLEEP_EVENT_S0IX_RESUME ) )
buf . msg . insize = sizeof ( buf . u . resp1 ) ;
buf . msg . version = 1 ;
} else {
buf . u . req0 . sleep_event = sleep_event ;
buf . msg . outsize = sizeof ( buf . u . req0 ) ;
}
2016-12-16 18:57:37 +01:00
buf . msg . command = EC_CMD_HOST_SLEEP_EVENT ;
2020-02-20 16:58:58 +01:00
ret = cros_ec_cmd_xfer_status ( ec_dev , & buf . msg ) ;
2022-06-14 00:57:26 -07:00
/* Report failure to transition to system wide suspend with a warning. */
2019-04-03 14:34:28 -07:00
if ( ret > = 0 & & ec_dev - > host_sleep_v1 & &
2022-06-14 00:57:26 -07:00
( sleep_event = = HOST_SLEEP_EVENT_S0IX_RESUME | |
sleep_event = = HOST_SLEEP_EVENT_S3_RESUME ) ) {
2019-06-27 13:44:45 -07:00
ec_dev - > last_resume_result =
buf . u . resp1 . resume_response . sleep_transitions ;
2019-04-03 14:34:28 -07:00
WARN_ONCE ( buf . u . resp1 . resume_response . sleep_transitions &
EC_HOST_RESUME_SLEEP_TIMEOUT ,
2022-06-14 00:57:26 -07:00
" EC detected sleep transition timeout. Total sleep transitions: %d " ,
2019-04-03 14:34:28 -07:00
buf . u . resp1 . resume_response . sleep_transitions &
EC_HOST_RESUME_SLEEP_TRANSITIONS_MASK ) ;
2019-06-27 13:44:45 -07:00
}
2019-04-03 14:34:28 -07:00
return ret ;
2016-12-16 18:57:37 +01:00
}
2020-02-03 14:53:56 -08:00
static int cros_ec_ready_event ( struct notifier_block * nb ,
unsigned long queued_during_suspend ,
void * _notify )
{
struct cros_ec_device * ec_dev = container_of ( nb , struct cros_ec_device ,
notifier_ready ) ;
u32 host_event = cros_ec_get_host_event ( ec_dev ) ;
if ( host_event & EC_HOST_EVENT_MASK ( EC_HOST_EVENT_INTERFACE_READY ) ) {
mutex_lock ( & ec_dev - > lock ) ;
cros_ec_query_all ( ec_dev ) ;
mutex_unlock ( & ec_dev - > lock ) ;
return NOTIFY_OK ;
}
return NOTIFY_DONE ;
}
2019-11-19 13:45:45 +01:00
/**
* cros_ec_register ( ) - Register a new ChromeOS EC , using the provided info .
* @ ec_dev : Device to register .
*
* Before calling this , allocate a pointer to a new device and then fill
* in all the fields up to the - - private - - marker .
*
* Return : 0 on success or negative error code .
*/
2013-02-25 14:08:37 -08:00
int cros_ec_register ( struct cros_ec_device * ec_dev )
{
struct device * dev = ec_dev - > dev ;
int err = 0 ;
2016-08-10 19:05:24 +02:00
BLOCKING_INIT_NOTIFIER_HEAD ( & ec_dev - > event_notifier ) ;
2023-01-10 23:10:33 +01:00
BLOCKING_INIT_NOTIFIER_HEAD ( & ec_dev - > panic_notifier ) ;
2016-08-10 19:05:24 +02:00
2015-06-09 13:04:45 +02:00
ec_dev - > max_request = sizeof ( struct ec_params_hello ) ;
ec_dev - > max_response = sizeof ( struct ec_response_get_protocol_info ) ;
ec_dev - > max_passthru = 0 ;
2022-02-16 16:03:02 +08:00
ec_dev - > ec = NULL ;
ec_dev - > pd = NULL ;
2022-08-22 14:40:40 -07:00
ec_dev - > suspend_timeout_ms = EC_HOST_SLEEP_TIMEOUT_DEFAULT ;
2015-06-09 13:04:45 +02:00
ec_dev - > din = devm_kzalloc ( dev , ec_dev - > din_size , GFP_KERNEL ) ;
if ( ! ec_dev - > din )
return - ENOMEM ;
ec_dev - > dout = devm_kzalloc ( dev , ec_dev - > dout_size , GFP_KERNEL ) ;
if ( ! ec_dev - > dout )
return - ENOMEM ;
2013-02-25 14:08:37 -08:00
2023-01-11 15:41:46 +08:00
lockdep_register_key ( & ec_dev - > lockdep_key ) ;
2014-09-18 17:18:57 +02:00
mutex_init ( & ec_dev - > lock ) ;
2023-01-11 15:41:46 +08:00
lockdep_set_class ( & ec_dev - > lock , & ec_dev - > lockdep_key ) ;
2014-09-18 17:18:57 +02:00
2018-04-18 12:23:58 +02:00
err = cros_ec_query_all ( ec_dev ) ;
if ( err ) {
dev_err ( dev , " Cannot identify the EC: error %d \n " , err ) ;
2023-03-08 11:12:47 +08:00
goto exit ;
2018-04-18 12:23:58 +02:00
}
2015-06-09 13:04:45 +02:00
2019-11-19 13:45:46 +01:00
if ( ec_dev - > irq > 0 ) {
2019-11-19 13:45:46 +01:00
err = devm_request_threaded_irq ( dev , ec_dev - > irq ,
2021-01-21 21:46:36 -08:00
cros_ec_irq_handler ,
cros_ec_irq_thread ,
2019-11-19 13:45:46 +01:00
IRQF_TRIGGER_LOW | IRQF_ONESHOT ,
" chromeos-ec " , ec_dev ) ;
2016-08-10 19:05:24 +02:00
if ( err ) {
2022-02-16 16:03:06 +08:00
dev_err ( dev , " Failed to request IRQ %d: %d \n " ,
2016-08-10 19:05:24 +02:00
ec_dev - > irq , err ) ;
2023-03-08 11:12:47 +08:00
goto exit ;
2016-08-10 19:05:24 +02:00
}
}
2019-09-02 11:53:00 +02:00
/* Register a platform device for the main EC instance */
ec_dev - > ec = platform_device_register_data ( ec_dev - > dev , " cros-ec-dev " ,
PLATFORM_DEVID_AUTO , & ec_p ,
sizeof ( struct cros_ec_platform ) ) ;
if ( IS_ERR ( ec_dev - > ec ) ) {
dev_err ( ec_dev - > dev ,
" Failed to create CrOS EC platform device \n " ) ;
2023-01-11 15:41:46 +08:00
err = PTR_ERR ( ec_dev - > ec ) ;
2023-03-08 11:12:47 +08:00
goto exit ;
2013-02-25 14:08:37 -08:00
}
2015-06-09 13:04:47 +02:00
if ( ec_dev - > max_passthru ) {
/*
2019-09-02 11:53:00 +02:00
* Register a platform device for the PD behind the main EC .
2015-06-09 13:04:47 +02:00
* We make the following assumptions :
* - behind an EC , we have a pd
* - only one device added .
* - the EC is responsive at init time ( it is not true for a
2019-09-02 11:53:00 +02:00
* sensor hub ) .
2015-06-09 13:04:47 +02:00
*/
2019-09-02 11:53:00 +02:00
ec_dev - > pd = platform_device_register_data ( ec_dev - > dev ,
" cros-ec-dev " ,
PLATFORM_DEVID_AUTO , & pd_p ,
sizeof ( struct cros_ec_platform ) ) ;
if ( IS_ERR ( ec_dev - > pd ) ) {
dev_err ( ec_dev - > dev ,
" Failed to create CrOS PD platform device \n " ) ;
2022-02-16 16:03:02 +08:00
err = PTR_ERR ( ec_dev - > pd ) ;
goto exit ;
2015-06-09 13:04:47 +02:00
}
}
2015-05-20 11:31:28 +02:00
if ( IS_ENABLED ( CONFIG_OF ) & & dev - > of_node ) {
2017-05-29 17:45:55 +02:00
err = devm_of_platform_populate ( dev ) ;
2015-05-20 11:31:28 +02:00
if ( err ) {
dev_err ( dev , " Failed to register sub-devices \n " ) ;
2022-02-16 16:03:02 +08:00
goto exit ;
2015-05-20 11:31:28 +02:00
}
}
2016-12-16 18:57:37 +01:00
/*
* Clear sleep event - this will fail harmlessly on platforms that
* don ' t implement the sleep event host command .
*/
err = cros_ec_sleep_event ( ec_dev , 0 ) ;
if ( err < 0 )
2022-02-16 16:03:06 +08:00
dev_dbg ( ec_dev - > dev , " Error %d clearing sleep event to ec \n " ,
2016-12-16 18:57:37 +01:00
err ) ;
2020-02-03 14:53:56 -08:00
if ( ec_dev - > mkbp_event_supported ) {
/*
* Register the notifier for EC_HOST_EVENT_INTERFACE_READY
* event .
*/
ec_dev - > notifier_ready . notifier_call = cros_ec_ready_event ;
err = blocking_notifier_chain_register ( & ec_dev - > event_notifier ,
& ec_dev - > notifier_ready ) ;
if ( err )
2022-02-16 16:03:02 +08:00
goto exit ;
2020-02-03 14:53:56 -08:00
}
2014-06-18 11:14:03 -07:00
dev_info ( dev , " Chrome EC device registered \n " ) ;
2013-02-25 14:08:37 -08:00
2021-01-21 21:46:37 -08:00
/*
* Unlock EC that may be waiting for AP to process MKBP events .
* If the AP takes to long to answer , the EC would stop sending events .
*/
if ( ec_dev - > mkbp_event_supported )
cros_ec_irq_thread ( 0 , ec_dev ) ;
2013-02-25 14:08:37 -08:00
return 0 ;
2022-02-16 16:03:02 +08:00
exit :
platform_device_unregister ( ec_dev - > ec ) ;
platform_device_unregister ( ec_dev - > pd ) ;
2023-01-11 15:41:46 +08:00
mutex_destroy ( & ec_dev - > lock ) ;
lockdep_unregister_key ( & ec_dev - > lockdep_key ) ;
2022-02-16 16:03:02 +08:00
return err ;
2013-02-25 14:08:37 -08:00
}
2013-03-20 09:46:15 +01:00
EXPORT_SYMBOL ( cros_ec_register ) ;
2013-02-25 14:08:37 -08:00
2019-11-19 13:45:45 +01:00
/**
* cros_ec_unregister ( ) - Remove a ChromeOS EC .
* @ ec_dev : Device to unregister .
*
* Call this to deregister a ChromeOS EC , then clean up any private data .
*
* Return : 0 on success or negative error code .
*/
2022-01-23 18:52:00 +01:00
void cros_ec_unregister ( struct cros_ec_device * ec_dev )
2019-09-02 11:53:00 +02:00
{
2023-03-08 11:12:47 +08:00
platform_device_unregister ( ec_dev - > pd ) ;
2019-09-02 11:53:00 +02:00
platform_device_unregister ( ec_dev - > ec ) ;
2023-01-11 15:41:46 +08:00
mutex_destroy ( & ec_dev - > lock ) ;
lockdep_unregister_key ( & ec_dev - > lockdep_key ) ;
2019-09-02 11:53:00 +02:00
}
EXPORT_SYMBOL ( cros_ec_unregister ) ;
2013-02-25 14:08:37 -08:00
# ifdef CONFIG_PM_SLEEP
2023-10-27 16:02:22 -05:00
static void cros_ec_send_suspend_event ( struct cros_ec_device * ec_dev )
2013-02-25 14:08:37 -08:00
{
2016-12-16 18:57:37 +01:00
int ret ;
u8 sleep_event ;
2018-02-22 13:30:52 -08:00
sleep_event = ( ! IS_ENABLED ( CONFIG_ACPI ) | | pm_suspend_via_firmware ( ) ) ?
HOST_SLEEP_EVENT_S3_SUSPEND :
HOST_SLEEP_EVENT_S0IX_SUSPEND ;
2016-12-16 18:57:37 +01:00
ret = cros_ec_sleep_event ( ec_dev , sleep_event ) ;
if ( ret < 0 )
2022-02-16 16:03:06 +08:00
dev_dbg ( ec_dev - > dev , " Error %d sending suspend event to ec \n " ,
2016-12-16 18:57:37 +01:00
ret ) ;
2023-10-27 16:02:22 -05:00
}
2013-02-25 14:08:37 -08:00
2023-10-27 16:02:22 -05:00
/**
* cros_ec_suspend_prepare ( ) - Handle a suspend prepare operation for the ChromeOS EC device .
* @ ec_dev : Device to suspend .
*
* This can be called by drivers to handle a suspend prepare stage of suspend .
*
* Return : 0 always .
*/
int cros_ec_suspend_prepare ( struct cros_ec_device * ec_dev )
{
cros_ec_send_suspend_event ( ec_dev ) ;
return 0 ;
}
EXPORT_SYMBOL ( cros_ec_suspend_prepare ) ;
static void cros_ec_disable_irq ( struct cros_ec_device * ec_dev )
{
struct device * dev = ec_dev - > dev ;
2013-02-25 14:08:37 -08:00
if ( device_may_wakeup ( dev ) )
ec_dev - > wake_enabled = ! enable_irq_wake ( ec_dev - > irq ) ;
2022-02-16 16:03:04 +08:00
else
ec_dev - > wake_enabled = false ;
2013-02-25 14:08:37 -08:00
disable_irq ( ec_dev - > irq ) ;
2016-12-16 18:57:36 +01:00
ec_dev - > suspended = true ;
2023-10-27 16:02:22 -05:00
}
2013-02-25 14:08:37 -08:00
2023-10-27 16:02:22 -05:00
/**
* cros_ec_suspend_late ( ) - Handle a suspend late operation for the ChromeOS EC device .
* @ ec_dev : Device to suspend .
*
* This can be called by drivers to handle a suspend late stage of suspend .
*
* Return : 0 always .
*/
int cros_ec_suspend_late ( struct cros_ec_device * ec_dev )
{
cros_ec_disable_irq ( ec_dev ) ;
return 0 ;
}
EXPORT_SYMBOL ( cros_ec_suspend_late ) ;
/**
* cros_ec_suspend ( ) - Handle a suspend operation for the ChromeOS EC device .
* @ ec_dev : Device to suspend .
*
* This can be called by drivers to handle a suspend event .
*
* Return : 0 always .
*/
int cros_ec_suspend ( struct cros_ec_device * ec_dev )
{
2024-04-30 10:09:24 +08:00
cros_ec_suspend_prepare ( ec_dev ) ;
cros_ec_suspend_late ( ec_dev ) ;
2013-02-25 14:08:37 -08:00
return 0 ;
}
2013-03-20 09:46:15 +01:00
EXPORT_SYMBOL ( cros_ec_suspend ) ;
2013-02-25 14:08:37 -08:00
2018-05-30 12:22:04 -07:00
static void cros_ec_report_events_during_suspend ( struct cros_ec_device * ec_dev )
2016-08-10 19:05:24 +02:00
{
2022-09-13 20:49:54 +00:00
bool wake_event ;
2018-08-20 08:34:19 -07:00
while ( ec_dev - > mkbp_event_supported & &
2022-09-13 20:49:54 +00:00
cros_ec_get_next_event ( ec_dev , & wake_event , NULL ) > 0 ) {
2016-08-10 19:05:24 +02:00
blocking_notifier_call_chain ( & ec_dev - > event_notifier ,
1 , ec_dev ) ;
2022-09-13 20:49:54 +00:00
if ( wake_event & & device_may_wakeup ( ec_dev - > dev ) )
pm_wakeup_event ( ec_dev - > dev , 0 ) ;
}
2016-08-10 19:05:24 +02:00
}
2023-10-27 16:02:22 -05:00
static void cros_ec_send_resume_event ( struct cros_ec_device * ec_dev )
2013-02-25 14:08:37 -08:00
{
2016-12-16 18:57:37 +01:00
int ret ;
u8 sleep_event ;
2017-01-13 16:04:32 +01:00
sleep_event = ( ! IS_ENABLED ( CONFIG_ACPI ) | | pm_suspend_via_firmware ( ) ) ?
HOST_SLEEP_EVENT_S3_RESUME :
HOST_SLEEP_EVENT_S0IX_RESUME ;
2016-12-16 18:57:37 +01:00
ret = cros_ec_sleep_event ( ec_dev , sleep_event ) ;
if ( ret < 0 )
2022-02-16 16:03:06 +08:00
dev_dbg ( ec_dev - > dev , " Error %d sending resume event to ec \n " ,
2016-12-16 18:57:37 +01:00
ret ) ;
2023-10-27 16:02:22 -05:00
}
/**
* cros_ec_resume_complete ( ) - Handle a resume complete operation for the ChromeOS EC device .
* @ ec_dev : Device to resume .
*
* This can be called by drivers to handle a resume complete stage of resume .
*/
void cros_ec_resume_complete ( struct cros_ec_device * ec_dev )
{
cros_ec_send_resume_event ( ec_dev ) ;
2024-04-29 12:13:45 -06:00
/*
* Let the mfd devices know about events that occur during
* suspend . This way the clients know what to do with them .
*/
cros_ec_report_events_during_suspend ( ec_dev ) ;
2023-10-27 16:02:22 -05:00
}
EXPORT_SYMBOL ( cros_ec_resume_complete ) ;
static void cros_ec_enable_irq ( struct cros_ec_device * ec_dev )
{
ec_dev - > suspended = false ;
enable_irq ( ec_dev - > irq ) ;
2016-12-16 18:57:37 +01:00
2022-02-16 16:03:04 +08:00
if ( ec_dev - > wake_enabled )
2013-02-25 14:08:37 -08:00
disable_irq_wake ( ec_dev - > irq ) ;
2023-10-27 16:02:22 -05:00
}
2018-05-30 12:22:04 -07:00
2023-10-27 16:02:22 -05:00
/**
* cros_ec_resume_early ( ) - Handle a resume early operation for the ChromeOS EC device .
* @ ec_dev : Device to resume .
*
* This can be called by drivers to handle a resume early stage of resume .
*
* Return : 0 always .
*/
int cros_ec_resume_early ( struct cros_ec_device * ec_dev )
{
cros_ec_enable_irq ( ec_dev ) ;
return 0 ;
}
EXPORT_SYMBOL ( cros_ec_resume_early ) ;
2013-02-25 14:08:37 -08:00
2023-10-27 16:02:22 -05:00
/**
* cros_ec_resume ( ) - Handle a resume operation for the ChromeOS EC device .
* @ ec_dev : Device to resume .
*
* This can be called by drivers to handle a resume event .
*
* Return : 0 always .
*/
int cros_ec_resume ( struct cros_ec_device * ec_dev )
{
2024-04-29 12:13:45 -06:00
cros_ec_resume_early ( ec_dev ) ;
cros_ec_resume_complete ( ec_dev ) ;
2013-02-25 14:08:37 -08:00
return 0 ;
}
2013-03-20 09:46:15 +01:00
EXPORT_SYMBOL ( cros_ec_resume ) ;
2013-02-25 14:08:37 -08:00
# endif
2014-04-17 12:32:17 -07:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " ChromeOS EC core driver " ) ;