diff options
-rw-r--r-- | drivers/platform/chrome/cros_ec_lpc_mec.c | 76 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_lpc_mec.h | 11 |
2 files changed, 85 insertions, 2 deletions
diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.c b/drivers/platform/chrome/cros_ec_lpc_mec.c index 395dc3a6fb5e..dfad934e65ca 100644 --- a/drivers/platform/chrome/cros_ec_lpc_mec.c +++ b/drivers/platform/chrome/cros_ec_lpc_mec.c @@ -10,14 +10,66 @@ #include "cros_ec_lpc_mec.h" +#define ACPI_LOCK_DELAY_MS 500 + /* * This mutex must be held while accessing the EMI unit. We can't rely on the * EC mutex because memmap data may be accessed without it being held. */ static DEFINE_MUTEX(io_mutex); +/* + * An alternative mutex to be used when the ACPI AML code may also + * access memmap data. When set, this mutex is used in preference to + * io_mutex. + */ +static acpi_handle aml_mutex; + static u16 mec_emi_base, mec_emi_end; /** + * cros_ec_lpc_mec_lock() - Acquire mutex for EMI + * + * @return: Negative error code, or zero for success + */ +static int cros_ec_lpc_mec_lock(void) +{ + bool success; + + if (!aml_mutex) { + mutex_lock(&io_mutex); + return 0; + } + + success = ACPI_SUCCESS(acpi_acquire_mutex(aml_mutex, + NULL, ACPI_LOCK_DELAY_MS)); + if (!success) + return -EBUSY; + + return 0; +} + +/** + * cros_ec_lpc_mec_unlock() - Release mutex for EMI + * + * @return: Negative error code, or zero for success + */ +static int cros_ec_lpc_mec_unlock(void) +{ + bool success; + + if (!aml_mutex) { + mutex_unlock(&io_mutex); + return 0; + } + + success = ACPI_SUCCESS(acpi_release_mutex(aml_mutex, NULL)); + if (!success) + return -EBUSY; + + return 0; +} + +/** * cros_ec_lpc_mec_emi_write_address() - Initialize EMI at a given address. * * @addr: Starting read / write address @@ -78,6 +130,7 @@ int cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, int io_addr; u8 sum = 0; enum cros_ec_lpc_mec_emi_access_mode access, new_access; + int ret; /* Return checksum of 0 if window is not initialized */ WARN_ON(mec_emi_base == 0 || mec_emi_end == 0); @@ -93,7 +146,9 @@ int cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, else access = ACCESS_TYPE_LONG_AUTO_INCREMENT; - mutex_lock(&io_mutex); + ret = cros_ec_lpc_mec_lock(); + if (ret) + return ret; /* Initialize I/O at desired address */ cros_ec_lpc_mec_emi_write_address(offset, access); @@ -135,7 +190,9 @@ int cros_ec_lpc_io_bytes_mec(enum cros_ec_lpc_mec_io_type io_type, } done: - mutex_unlock(&io_mutex); + ret = cros_ec_lpc_mec_unlock(); + if (ret) + return ret; return sum; } @@ -147,3 +204,18 @@ void cros_ec_lpc_mec_init(unsigned int base, unsigned int end) mec_emi_end = end; } EXPORT_SYMBOL(cros_ec_lpc_mec_init); + +int cros_ec_lpc_mec_acpi_mutex(struct acpi_device *adev, const char *pathname) +{ + int status; + + if (!adev) + return -ENOENT; + + status = acpi_get_handle(adev->handle, pathname, &aml_mutex); + if (ACPI_FAILURE(status)) + return -ENOENT; + + return 0; +} +EXPORT_SYMBOL(cros_ec_lpc_mec_acpi_mutex); diff --git a/drivers/platform/chrome/cros_ec_lpc_mec.h b/drivers/platform/chrome/cros_ec_lpc_mec.h index 69670832f187..69f9d8786f61 100644 --- a/drivers/platform/chrome/cros_ec_lpc_mec.h +++ b/drivers/platform/chrome/cros_ec_lpc_mec.h @@ -8,6 +8,8 @@ #ifndef __CROS_EC_LPC_MEC_H #define __CROS_EC_LPC_MEC_H +#include <linux/acpi.h> + enum cros_ec_lpc_mec_emi_access_mode { /* 8-bit access */ ACCESS_TYPE_BYTE = 0x0, @@ -46,6 +48,15 @@ enum cros_ec_lpc_mec_io_type { void cros_ec_lpc_mec_init(unsigned int base, unsigned int end); /** + * cros_ec_lpc_mec_acpi_mutex() - Find and set ACPI mutex for MEC + * + * @adev: Parent ACPI device + * @pathname: Name of AML mutex + * @return: Negative error code, or zero for success + */ +int cros_ec_lpc_mec_acpi_mutex(struct acpi_device *adev, const char *pathname); + +/** * cros_ec_lpc_mec_in_range() - Determine if addresses are in MEC EMI range. * * @offset: Address offset |