mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 08:14:15 +08:00
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:
commit
1fca7e0e6f
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
44
drivers/acpi/pmic/intel_pmic_chtcrc.c
Normal file
44
drivers/acpi/pmic/intel_pmic_chtcrc.c
Normal 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);
|
@ -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",
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user