Merge branches 'acpi-ec', 'acpi-soc', 'acpi-pmic' and 'acpi-button'

* acpi-ec:
  ACPI: EC: add support for hardware-reduced systems
  ACPI: EC: tweak naming in preparation for GpioInt support

* acpi-soc:
  ACPI: LPSS: Add dmi quirk for skipping _DEP check for some device-links
  ACPI: LPSS: Add LNXVIDEO -> BYT I2C1 to lpss_device_links
  ACPI: LPSS: Add LNXVIDEO -> BYT I2C7 to lpss_device_links

* acpi-pmic:
  ACPI / PMIC: Add Cherry Trail Crystal Cove PMIC OpRegion driver
  ACPI / PMIC: Add byt prefix to Crystal Cove PMIC OpRegion driver
  ACPI / PMIC: Do not register handlers for unhandled OpRegions

* acpi-button:
  ACPI: button: Remove unused acpi_lid_notifier_[un]register() functions
  ACPI: button: Add DMI quirk for Asus T200TA
  ACPI: button: Add DMI quirk for Medion Akoya E2215T
  ACPI: button: Turn lid_blacklst DMI table into a generic quirk table
  ACPI: button: Allow disabling LID support with the lid_init_state module option
  ACPI: button: Refactor lid_init_state module parsing code
This commit is contained in:
Rafael J. Wysocki 2019-11-26 10:30:12 +01:00
11 changed files with 313 additions and 148 deletions

View File

@ -513,11 +513,19 @@ menuconfig PMIC_OPREGION
PMIC chip.
if PMIC_OPREGION
config CRC_PMIC_OPREGION
bool "ACPI operation region support for CrystalCove PMIC"
config BYTCRC_PMIC_OPREGION
bool "ACPI operation region support for Bay Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for CrystalCove PMIC.
This config adds ACPI operation region support for the Bay Trail
version of the Crystal Cove PMIC.
config CHTCRC_PMIC_OPREGION
bool "ACPI operation region support for Cherry Trail Crystal Cove PMIC"
depends on INTEL_SOC_PMIC
help
This config adds ACPI operation region support for the Cherry Trail
version of the Crystal Cove PMIC.
config XPOWER_PMIC_OPREGION
bool "ACPI operation region support for XPower AXP288 PMIC"

View File

@ -109,7 +109,8 @@ obj-$(CONFIG_ACPI_APEI) += apei/
obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o
obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
obj-$(CONFIG_BYTCRC_PMIC_OPREGION) += pmic/intel_pmic_bytcrc.o
obj-$(CONFIG_CHTCRC_PMIC_OPREGION) += pmic/intel_pmic_chtcrc.o
obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
obj-$(CONFIG_BXT_WC_PMIC_OPREGION) += pmic/intel_pmic_bxtwc.o
obj-$(CONFIG_CHT_WC_PMIC_OPREGION) += pmic/intel_pmic_chtwc.o

View File

@ -10,6 +10,7 @@
#include <linux/acpi.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/dmi.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/mutex.h>
@ -463,6 +464,18 @@ struct lpss_device_links {
const char *consumer_hid;
const char *consumer_uid;
u32 flags;
const struct dmi_system_id *dep_missing_ids;
};
/* Please keep this list sorted alphabetically by vendor and model */
static const struct dmi_system_id i2c1_dep_missing_dmi_ids[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
},
},
{}
};
/*
@ -473,9 +486,17 @@ struct lpss_device_links {
* the supplier is not enumerated until after the consumer is probed.
*/
static const struct lpss_device_links lpss_device_links[] = {
/* CHT External sdcard slot controller depends on PMIC I2C ctrl */
{"808622C1", "7", "80860F14", "3", DL_FLAG_PM_RUNTIME},
/* CHT iGPU depends on PMIC I2C controller */
{"808622C1", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
/* BYT iGPU depends on the Embedded Controller I2C controller (UID 1) */
{"80860F41", "1", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME,
i2c1_dep_missing_dmi_ids},
/* BYT CR iGPU depends on PMIC I2C controller (UID 5 on CR) */
{"80860F41", "5", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
/* BYT iGPU depends on PMIC I2C controller (UID 7 on non CR) */
{"80860F41", "7", "LNXVIDEO", NULL, DL_FLAG_PM_RUNTIME},
};
static bool hid_uid_match(struct acpi_device *adev,
@ -570,7 +591,8 @@ static void acpi_lpss_link_consumer(struct device *dev1,
if (!dev2)
return;
if (acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
|| acpi_lpss_dep(ACPI_COMPANION(dev2), ACPI_HANDLE(dev1)))
device_link_add(dev2, dev1, link->flags);
put_device(dev2);
@ -585,7 +607,8 @@ static void acpi_lpss_link_supplier(struct device *dev1,
if (!dev2)
return;
if (acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
if ((link->dep_missing_ids && dmi_check_system(link->dep_missing_ids))
|| acpi_lpss_dep(ACPI_COMPANION(dev1), ACPI_HANDLE(dev2)))
device_link_add(dev1, dev2, link->flags);
put_device(dev2);

View File

@ -44,9 +44,19 @@
#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
#define ACPI_BUTTON_TYPE_LID 0x05
#define ACPI_BUTTON_LID_INIT_IGNORE 0x00
#define ACPI_BUTTON_LID_INIT_OPEN 0x01
#define ACPI_BUTTON_LID_INIT_METHOD 0x02
enum {
ACPI_BUTTON_LID_INIT_IGNORE,
ACPI_BUTTON_LID_INIT_OPEN,
ACPI_BUTTON_LID_INIT_METHOD,
ACPI_BUTTON_LID_INIT_DISABLED,
};
static const char * const lid_init_state_str[] = {
[ACPI_BUTTON_LID_INIT_IGNORE] = "ignore",
[ACPI_BUTTON_LID_INIT_OPEN] = "open",
[ACPI_BUTTON_LID_INIT_METHOD] = "method",
[ACPI_BUTTON_LID_INIT_DISABLED] = "disabled",
};
#define _COMPONENT ACPI_BUTTON_COMPONENT
ACPI_MODULE_NAME("button");
@ -65,18 +75,39 @@ static const struct acpi_device_id button_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, button_device_ids);
/*
* Some devices which don't even have a lid in anyway have a broken _LID
* method (e.g. pointing to a floating gpio pin) causing spurious LID events.
*/
static const struct dmi_system_id lid_blacklst[] = {
/* Please keep this list sorted alphabetically by vendor and model */
static const struct dmi_system_id dmi_lid_quirks[] = {
{
/* GP-electronic T701 */
/*
* Asus T200TA, _LID keeps reporting closed after every second
* openening of the lid. Causing immediate re-suspend after
* opening every other open. Using LID_INIT_OPEN fixes this.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "T200TA"),
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
},
{
/* GP-electronic T701, _LID method points to a floating GPIO */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_MATCH(DMI_PRODUCT_NAME, "T701"),
DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"),
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
},
{
/*
* Medion Akoya E2215T, notification of the LID device only
* happens on close, not on open and _LID always returns closed.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
DMI_MATCH(DMI_PRODUCT_NAME, "E2215T MD60198"),
},
.driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_OPEN,
},
{}
};
@ -116,9 +147,8 @@ struct acpi_button {
bool suspended;
};
static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier);
static struct acpi_device *lid_device;
static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
static long lid_init_state = -1;
static unsigned long lid_report_interval __read_mostly = 500;
module_param(lid_report_interval, ulong, 0644);
@ -146,7 +176,6 @@ static int acpi_lid_evaluate_state(struct acpi_device *device)
static int acpi_lid_notify_state(struct acpi_device *device, int state)
{
struct acpi_button *button = acpi_driver_data(device);
int ret;
ktime_t next_report;
bool do_update;
@ -223,18 +252,7 @@ static int acpi_lid_notify_state(struct acpi_device *device, int state)
button->last_time = ktime_get();
}
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, device);
if (ret == NOTIFY_DONE)
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
device);
if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
/*
* It is also regarded as success if the notifier_chain
* returns NOTIFY_OK or NOTIFY_DONE.
*/
ret = 0;
}
return ret;
return 0;
}
static int __maybe_unused acpi_button_state_seq_show(struct seq_file *seq,
@ -331,18 +349,6 @@ static int acpi_button_remove_fs(struct acpi_device *device)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
int acpi_lid_notifier_register(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&acpi_lid_notifier, nb);
}
EXPORT_SYMBOL(acpi_lid_notifier_register);
int acpi_lid_notifier_unregister(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&acpi_lid_notifier, nb);
}
EXPORT_SYMBOL(acpi_lid_notifier_unregister);
int acpi_lid_open(void)
{
if (!lid_device)
@ -472,7 +478,8 @@ static int acpi_button_add(struct acpi_device *device)
char *name, *class;
int error;
if (!strcmp(hid, ACPI_BUTTON_HID_LID) && dmi_check_system(lid_blacklst))
if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
return -ENODEV;
button = kzalloc(sizeof(struct acpi_button), GFP_KERNEL);
@ -578,36 +585,30 @@ static int acpi_button_remove(struct acpi_device *device)
static int param_set_lid_init_state(const char *val,
const struct kernel_param *kp)
{
int result = 0;
int i;
if (!strncmp(val, "open", sizeof("open") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_OPEN;
pr_info("Notify initial lid state as open\n");
} else if (!strncmp(val, "method", sizeof("method") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
pr_info("Notify initial lid state with _LID return value\n");
} else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) {
lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE;
pr_info("Do not notify initial lid state\n");
} else
result = -EINVAL;
return result;
i = sysfs_match_string(lid_init_state_str, val);
if (i < 0)
return i;
lid_init_state = i;
pr_info("Initial lid state set to '%s'\n", lid_init_state_str[i]);
return 0;
}
static int param_get_lid_init_state(char *buffer,
const struct kernel_param *kp)
static int param_get_lid_init_state(char *buf, const struct kernel_param *kp)
{
switch (lid_init_state) {
case ACPI_BUTTON_LID_INIT_OPEN:
return sprintf(buffer, "open");
case ACPI_BUTTON_LID_INIT_METHOD:
return sprintf(buffer, "method");
case ACPI_BUTTON_LID_INIT_IGNORE:
return sprintf(buffer, "ignore");
default:
return sprintf(buffer, "invalid");
}
return 0;
int i, c = 0;
for (i = 0; i < ARRAY_SIZE(lid_init_state_str); i++)
if (i == lid_init_state)
c += sprintf(buf + c, "[%s] ", lid_init_state_str[i]);
else
c += sprintf(buf + c, "%s ", lid_init_state_str[i]);
buf[c - 1] = '\n'; /* Replace the final space with a newline */
return c;
}
module_param_call(lid_init_state,
@ -617,6 +618,16 @@ MODULE_PARM_DESC(lid_init_state, "Behavior for reporting LID initial state");
static int acpi_button_register_driver(struct acpi_driver *driver)
{
const struct dmi_system_id *dmi_id;
if (lid_init_state == -1) {
dmi_id = dmi_first_match(dmi_lid_quirks);
if (dmi_id)
lid_init_state = (long)dmi_id->driver_data;
else
lid_init_state = ACPI_BUTTON_LID_INIT_METHOD;
}
/*
* Modules such as nouveau.ko and i915.ko have a link time dependency
* on acpi_lid_open(), and would therefore not be loadable on ACPI

View File

@ -95,12 +95,12 @@ enum {
EC_FLAGS_QUERY_ENABLED, /* Query is enabled */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_QUERY_GUARDING, /* Guard for SCI_EVT check */
EC_FLAGS_GPE_HANDLER_INSTALLED, /* GPE handler installed */
EC_FLAGS_EVENT_HANDLER_INSTALLED, /* Event handler installed */
EC_FLAGS_EC_HANDLER_INSTALLED, /* OpReg handler installed */
EC_FLAGS_EVT_HANDLER_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_QUERY_METHODS_INSTALLED, /* _Qxx handlers installed */
EC_FLAGS_STARTED, /* Driver is started */
EC_FLAGS_STOPPED, /* Driver is stopped */
EC_FLAGS_GPE_MASKED, /* GPE masked */
EC_FLAGS_EVENTS_MASKED, /* Events masked */
};
#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
@ -397,8 +397,8 @@ static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
static void acpi_ec_submit_request(struct acpi_ec *ec)
{
ec->reference_count++;
if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
ec->reference_count == 1)
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
ec->gpe >= 0 && ec->reference_count == 1)
acpi_ec_enable_gpe(ec, true);
}
@ -407,28 +407,36 @@ static void acpi_ec_complete_request(struct acpi_ec *ec)
bool flushed = false;
ec->reference_count--;
if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags) &&
ec->reference_count == 0)
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags) &&
ec->gpe >= 0 && ec->reference_count == 0)
acpi_ec_disable_gpe(ec, true);
flushed = acpi_ec_flushed(ec);
if (flushed)
wake_up(&ec->wait);
}
static void acpi_ec_mask_gpe(struct acpi_ec *ec)
static void acpi_ec_mask_events(struct acpi_ec *ec)
{
if (!test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
acpi_ec_disable_gpe(ec, false);
if (!test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
if (ec->gpe >= 0)
acpi_ec_disable_gpe(ec, false);
else
disable_irq_nosync(ec->irq);
ec_dbg_drv("Polling enabled");
set_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
set_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
}
}
static void acpi_ec_unmask_gpe(struct acpi_ec *ec)
static void acpi_ec_unmask_events(struct acpi_ec *ec)
{
if (test_bit(EC_FLAGS_GPE_MASKED, &ec->flags)) {
clear_bit(EC_FLAGS_GPE_MASKED, &ec->flags);
acpi_ec_enable_gpe(ec, false);
if (test_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags)) {
clear_bit(EC_FLAGS_EVENTS_MASKED, &ec->flags);
if (ec->gpe >= 0)
acpi_ec_enable_gpe(ec, false);
else
enable_irq(ec->irq);
ec_dbg_drv("Polling disabled");
}
}
@ -454,7 +462,7 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
static void acpi_ec_submit_query(struct acpi_ec *ec)
{
acpi_ec_mask_gpe(ec);
acpi_ec_mask_events(ec);
if (!acpi_ec_event_enabled(ec))
return;
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
@ -470,7 +478,7 @@ static void acpi_ec_complete_query(struct acpi_ec *ec)
if (test_and_clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
ec_dbg_evt("Command(%s) unblocked",
acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
acpi_ec_unmask_gpe(ec);
acpi_ec_unmask_events(ec);
}
static inline void __acpi_ec_enable_event(struct acpi_ec *ec)
@ -648,7 +656,9 @@ static void advance_transaction(struct acpi_ec *ec)
* ensure a hardware STS 0->1 change after this clearing can always
* trigger a GPE interrupt.
*/
acpi_ec_clear_gpe(ec);
if (ec->gpe >= 0)
acpi_ec_clear_gpe(ec);
status = acpi_ec_read_status(ec);
t = ec->curr;
/*
@ -717,7 +727,7 @@ err:
++t->irq_count;
/* Allow triggering on 0 threshold */
if (t->irq_count == ec_storm_threshold)
acpi_ec_mask_gpe(ec);
acpi_ec_mask_events(ec);
}
}
out:
@ -815,7 +825,7 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
spin_lock_irqsave(&ec->lock, tmp);
if (t->irq_count == ec_storm_threshold)
acpi_ec_unmask_gpe(ec);
acpi_ec_unmask_events(ec);
ec_dbg_req("Command(%s) stopped", acpi_ec_cmd_string(t->command));
ec->curr = NULL;
/* Disable GPE for command processing (IBF=0/OBF=1) */
@ -1275,18 +1285,28 @@ static void acpi_ec_event_handler(struct work_struct *work)
acpi_ec_check_event(ec);
}
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
u32 gpe_number, void *data)
static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
{
unsigned long flags;
struct acpi_ec *ec = data;
spin_lock_irqsave(&ec->lock, flags);
advance_transaction(ec);
spin_unlock_irqrestore(&ec->lock, flags);
}
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
u32 gpe_number, void *data)
{
acpi_ec_handle_interrupt(data);
return ACPI_INTERRUPT_HANDLED;
}
static irqreturn_t acpi_ec_irq_handler(int irq, void *data)
{
acpi_ec_handle_interrupt(data);
return IRQ_HANDLED;
}
/* --------------------------------------------------------------------------
* Address Space Management
* -------------------------------------------------------------------------- */
@ -1359,6 +1379,8 @@ static struct acpi_ec *acpi_ec_alloc(void)
ec->timestamp = jiffies;
ec->busy_polling = true;
ec->polling_guard = 0;
ec->gpe = -1;
ec->irq = -1;
return ec;
}
@ -1406,9 +1428,13 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
if (ACPI_FAILURE(status))
return status;
ec->gpe = tmp;
if (ACPI_SUCCESS(status))
ec->gpe = tmp;
/*
* Errors are non-fatal, allowing for ACPI Reduced Hardware
* platforms which use GpioInt instead of GPE.
*/
}
/* Use the global lock for all EC transactions? */
tmp = 0;
@ -1418,12 +1444,57 @@ ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
return AE_CTRL_TERMINATE;
}
static void install_gpe_event_handler(struct acpi_ec *ec)
{
acpi_status status =
acpi_install_gpe_raw_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler,
ec);
if (ACPI_SUCCESS(status)) {
/* This is not fatal as we can poll EC events */
set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
acpi_ec_leave_noirq(ec);
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
acpi_ec_enable_gpe(ec, true);
}
}
/* ACPI reduced hardware platforms use a GpioInt specified in _CRS. */
static int install_gpio_irq_event_handler(struct acpi_ec *ec,
struct acpi_device *device)
{
int irq = acpi_dev_gpio_irq_get(device, 0);
int ret;
if (irq < 0)
return irq;
ret = request_irq(irq, acpi_ec_irq_handler, IRQF_SHARED,
"ACPI EC", ec);
/*
* Unlike the GPE case, we treat errors here as fatal, we'll only
* implement GPIO polling if we find a case that needs it.
*/
if (ret < 0)
return ret;
ec->irq = irq;
set_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
acpi_ec_leave_noirq(ec);
return 0;
}
/*
* Note: This function returns an error code only when the address space
* handler is not installed, which means "not able to handle
* transactions".
*/
static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device,
bool handle_events)
{
acpi_status status;
@ -1456,24 +1527,23 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events)
if (!handle_events)
return 0;
if (!test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
/* Find and register all query methods */
acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
acpi_ec_register_query_methods,
NULL, ec, NULL);
set_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
set_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
}
if (!test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
/* This is not fatal as we can poll EC events */
if (ACPI_SUCCESS(status)) {
set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
acpi_ec_leave_noirq(ec);
if (test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
acpi_ec_enable_gpe(ec, true);
if (!test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
if (ec->gpe >= 0) {
install_gpe_event_handler(ec);
} else if (device) {
int ret = install_gpio_irq_event_handler(ec, device);
if (ret)
return ret;
} else { /* No GPE and no GpioInt? */
return -ENODEV;
}
}
/* EC is fully operational, allow queries */
@ -1504,23 +1574,29 @@ static void ec_remove_handlers(struct acpi_ec *ec)
*/
acpi_ec_stop(ec, false);
if (test_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags)) {
if (ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler)))
if (test_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags)) {
if (ec->gpe >= 0 &&
ACPI_FAILURE(acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler)))
pr_err("failed to remove gpe handler\n");
clear_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags);
if (ec->irq >= 0)
free_irq(ec->irq, ec);
clear_bit(EC_FLAGS_EVENT_HANDLER_INSTALLED, &ec->flags);
}
if (test_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags)) {
if (test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) {
acpi_ec_remove_query_handlers(ec, true, 0);
clear_bit(EC_FLAGS_EVT_HANDLER_INSTALLED, &ec->flags);
clear_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags);
}
}
static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device,
bool handle_events)
{
int ret;
ret = ec_install_handlers(ec, handle_events);
ret = ec_install_handlers(ec, device, handle_events);
if (ret)
return ret;
@ -1531,8 +1607,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events)
}
acpi_handle_info(ec->handle,
"GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
ec->gpe, ec->command_addr, ec->data_addr);
"GPE=0x%x, IRQ=%d, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n",
ec->gpe, ec->irq, ec->command_addr, ec->data_addr);
return ret;
}
@ -1596,7 +1672,7 @@ static int acpi_ec_add(struct acpi_device *device)
}
}
ret = acpi_ec_setup(ec, true);
ret = acpi_ec_setup(ec, device, true);
if (ret)
goto err_query;
@ -1716,7 +1792,7 @@ void __init acpi_ec_dsdt_probe(void)
* At this point, the GPE is not fully initialized, so do not to
* handle the events.
*/
ret = acpi_ec_setup(ec, false);
ret = acpi_ec_setup(ec, NULL, false);
if (ret) {
acpi_ec_free(ec);
return;
@ -1889,14 +1965,21 @@ void __init acpi_ec_ecdt_probe(void)
ec->command_addr = ecdt_ptr->control.address;
ec->data_addr = ecdt_ptr->data.address;
}
ec->gpe = ecdt_ptr->gpe;
/*
* Ignore the GPE value on Reduced Hardware platforms.
* Some products have this set to an erroneous value.
*/
if (!acpi_gbl_reduced_hardware)
ec->gpe = ecdt_ptr->gpe;
ec->handle = ACPI_ROOT_OBJECT;
/*
* At this point, the namespace is not initialized, so do not find
* the namespace objects, or handle the events.
*/
ret = acpi_ec_setup(ec, false);
ret = acpi_ec_setup(ec, NULL, false);
if (ret) {
acpi_ec_free(ec);
return;
@ -1928,7 +2011,7 @@ static int acpi_ec_suspend_noirq(struct device *dev)
* masked at the low level without side effects.
*/
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
ec->gpe >= 0 && ec->reference_count >= 1)
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
acpi_ec_enter_noirq(ec);
@ -1943,7 +2026,7 @@ static int acpi_ec_resume_noirq(struct device *dev)
acpi_ec_leave_noirq(ec);
if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
ec->reference_count >= 1)
ec->gpe >= 0 && ec->reference_count >= 1)
acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
return 0;

View File

@ -165,7 +165,8 @@ static inline void acpi_early_processor_osc(void) {}
-------------------------------------------------------------------------- */
struct acpi_ec {
acpi_handle handle;
u32 gpe;
int gpe;
int irq;
unsigned long command_addr;
unsigned long data_addr;
bool global_lock;

View File

@ -252,7 +252,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
struct regmap *regmap,
struct intel_pmic_opregion_data *d)
{
acpi_status status;
acpi_status status = AE_OK;
struct intel_pmic_opregion *opregion;
int ret;
@ -270,7 +270,8 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
opregion->regmap = regmap;
opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
status = acpi_install_address_space_handler(handle,
if (d->power_table_count)
status = acpi_install_address_space_handler(handle,
PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler,
NULL, opregion);
@ -279,7 +280,8 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
goto out_error;
}
status = acpi_install_address_space_handler(handle,
if (d->thermal_table_count)
status = acpi_install_address_space_handler(handle,
PMIC_THERMAL_OPREGION_ID,
intel_pmic_thermal_handler,
NULL, opregion);
@ -301,12 +303,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
return 0;
out_remove_thermal_handler:
acpi_remove_address_space_handler(handle, PMIC_THERMAL_OPREGION_ID,
intel_pmic_thermal_handler);
if (d->thermal_table_count)
acpi_remove_address_space_handler(handle,
PMIC_THERMAL_OPREGION_ID,
intel_pmic_thermal_handler);
out_remove_power_handler:
acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler);
if (d->power_table_count)
acpi_remove_address_space_handler(handle,
PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler);
out_error:
acpi_lpat_free_conversion_table(opregion->lpat_table);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Intel CrystalCove PMIC operation region driver
* Intel Bay Trail Crystal Cove PMIC operation region driver
*
* Copyright (C) 2014 Intel Corporation. All rights reserved.
*/
@ -295,7 +295,7 @@ static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
static struct platform_driver intel_crc_pmic_opregion_driver = {
.probe = intel_crc_pmic_opregion_probe,
.driver = {
.name = "crystal_cove_pmic",
.name = "byt_crystal_cove_pmic",
},
};
builtin_platform_driver(intel_crc_pmic_opregion_driver);

View File

@ -0,0 +1,44 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Intel Cherry Trail Crystal Cove PMIC operation region driver
*
* Copyright (C) 2019 Hans de Goede <hdegoede@redhat.com>
*/
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/mfd/intel_soc_pmic.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include "intel_pmic.h"
/*
* We have no docs for the CHT Crystal Cove PMIC. The Asus Zenfone-2 kernel
* code has 2 Crystal Cove regulator drivers, one calls the PMIC a "Crystal
* Cove Plus" PMIC and talks about Cherry Trail, so presuambly that one
* could be used to get register info for the regulators if we need to
* implement regulator support in the future.
*
* For now the sole purpose of this driver is to make
* intel_soc_pmic_exec_mipi_pmic_seq_element work on devices with a
* CHT Crystal Cove PMIC.
*/
static struct intel_pmic_opregion_data intel_chtcrc_pmic_opregion_data = {
.pmic_i2c_address = 0x6e,
};
static int intel_chtcrc_pmic_opregion_probe(struct platform_device *pdev)
{
struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
return intel_pmic_install_opregion_handler(&pdev->dev,
ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
&intel_chtcrc_pmic_opregion_data);
}
static struct platform_driver intel_chtcrc_pmic_opregion_driver = {
.probe = intel_chtcrc_pmic_opregion_probe,
.driver = {
.name = "cht_crystal_cove_pmic",
},
};
builtin_platform_driver(intel_chtcrc_pmic_opregion_driver);

View File

@ -75,7 +75,7 @@ static struct mfd_cell crystal_cove_byt_dev[] = {
.resources = gpio_resources,
},
{
.name = "crystal_cove_pmic",
.name = "byt_crystal_cove_pmic",
},
{
.name = "crystal_cove_pwm",

View File

@ -2,21 +2,9 @@
#ifndef ACPI_BUTTON_H
#define ACPI_BUTTON_H
#include <linux/notifier.h>
#if IS_ENABLED(CONFIG_ACPI_BUTTON)
extern int acpi_lid_notifier_register(struct notifier_block *nb);
extern int acpi_lid_notifier_unregister(struct notifier_block *nb);
extern int acpi_lid_open(void);
#else
static inline int acpi_lid_notifier_register(struct notifier_block *nb)
{
return 0;
}
static inline int acpi_lid_notifier_unregister(struct notifier_block *nb)
{
return 0;
}
static inline int acpi_lid_open(void)
{
return 1;