mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-07-23 17:47:28 +08:00
222 lines
6.4 KiB
Diff
222 lines
6.4 KiB
Diff
From 7c60cf26c675b90404782dcd54a91707ac100737 Mon Sep 17 00:00:00 2001
|
|
From: Hector Martin <marcan@marcan.st>
|
|
Date: Fri, 4 Mar 2022 19:21:19 +0900
|
|
Subject: [PATCH 149/171] Input: macsmc-hid: New driver to handle the Apple Mac
|
|
SMC buttons/lid
|
|
|
|
This driver implements power button and lid switch support for Apple Mac
|
|
devices using SMC controllers driven by the macsmc driver.
|
|
|
|
In addition to basic input support, this also responds to the final
|
|
shutdown warning (when the power button is held down long enough) by
|
|
doing an emergency kernel poweroff. This allows the NVMe controller to
|
|
be cleanly shut down, which prevents data loss for in-cache data.
|
|
|
|
Signed-off-by: Hector Martin <marcan@marcan.st>
|
|
---
|
|
drivers/input/misc/Kconfig | 12 +++
|
|
drivers/input/misc/Makefile | 1 +
|
|
drivers/input/misc/macsmc-hid.c | 157 ++++++++++++++++++++++++++++++++
|
|
3 files changed, 170 insertions(+)
|
|
create mode 100644 drivers/input/misc/macsmc-hid.c
|
|
|
|
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
|
|
index a18ab7358d8f..08e681473ae8 100644
|
|
--- a/drivers/input/misc/Kconfig
|
|
+++ b/drivers/input/misc/Kconfig
|
|
@@ -902,4 +902,16 @@ config INPUT_STPMIC1_ONKEY
|
|
To compile this driver as a module, choose M here: the
|
|
module will be called stpmic1_onkey.
|
|
|
|
+config INPUT_MACSMC_HID
|
|
+ tristate "Apple Mac SMC lid/buttons"
|
|
+ depends on APPLE_SMC
|
|
+ default ARCH_APPLE
|
|
+ help
|
|
+ Say Y here if you want to use the input events delivered via the
|
|
+ SMC controller on Apple Mac machines using the macsmc driver.
|
|
+ This includes lid open/close and the power button.
|
|
+
|
|
+ To compile this driver as a module, choose M here: the
|
|
+ module will be called macsmc-hid.
|
|
+
|
|
endif
|
|
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
|
|
index 28dfc444f0a9..a607c6472d0a 100644
|
|
--- a/drivers/input/misc/Makefile
|
|
+++ b/drivers/input/misc/Makefile
|
|
@@ -48,6 +48,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o
|
|
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
|
|
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
|
|
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
|
|
+obj-$(CONFIG_INPUT_MACSMC_HID) += macsmc-hid.o
|
|
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
|
|
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
|
|
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
|
|
diff --git a/drivers/input/misc/macsmc-hid.c b/drivers/input/misc/macsmc-hid.c
|
|
new file mode 100644
|
|
index 000000000000..1c0f7476081f
|
|
--- /dev/null
|
|
+++ b/drivers/input/misc/macsmc-hid.c
|
|
@@ -0,0 +1,157 @@
|
|
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
|
|
+/*
|
|
+ * Apple SMC input event driver
|
|
+ * Copyright The Asahi Linux Contributors
|
|
+ *
|
|
+ * This driver exposes HID events from the SMC as an input device.
|
|
+ * This includes the lid open/close and power button notifications.
|
|
+ */
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/input.h>
|
|
+#include <linux/mfd/core.h>
|
|
+#include <linux/mfd/macsmc.h>
|
|
+#include <linux/reboot.h>
|
|
+
|
|
+struct macsmc_hid {
|
|
+ struct device *dev;
|
|
+ struct apple_smc *smc;
|
|
+ struct input_dev *input;
|
|
+ struct notifier_block nb;
|
|
+};
|
|
+
|
|
+#define SMC_EV_BTN 0x7201
|
|
+#define SMC_EV_LID 0x7203
|
|
+
|
|
+#define BTN_POWER 0x06
|
|
+#define BTN_POWER_HELD1 0xfe
|
|
+#define BTN_POWER_HELD2 0x00
|
|
+
|
|
+static int macsmc_hid_event(struct notifier_block *nb, unsigned long event, void *data)
|
|
+{
|
|
+ struct macsmc_hid *smchid = container_of(nb, struct macsmc_hid, nb);
|
|
+ u16 type = event >> 16;
|
|
+ u8 d1 = (event >> 8) & 0xff;
|
|
+ u8 d2 = event & 0xff;
|
|
+
|
|
+ switch (type) {
|
|
+ case SMC_EV_BTN:
|
|
+ switch (d1) {
|
|
+ case BTN_POWER:
|
|
+ input_report_key(smchid->input, KEY_POWER, d2);
|
|
+ input_sync(smchid->input);
|
|
+ break;
|
|
+ case BTN_POWER_HELD1:
|
|
+ /*
|
|
+ * TODO: is this pre-warning useful?
|
|
+ */
|
|
+ if (d2)
|
|
+ dev_warn(smchid->dev, "Power button held down\n");
|
|
+ break;
|
|
+ case BTN_POWER_HELD2:
|
|
+ /*
|
|
+ * If we get here, we have about 4 seconds before forced shutdown.
|
|
+ * Try to do an emergency shutdown to make sure the NVMe cache is
|
|
+ * flushed. macOS actually does this by panicing (!)...
|
|
+ */
|
|
+ if (d2) {
|
|
+ dev_crit(smchid->dev, "Triggering forced shutdown!\n");
|
|
+ if (kernel_can_power_off())
|
|
+ kernel_power_off();
|
|
+ else /* Missing macsmc-reboot driver? */
|
|
+ kernel_restart("SMC power button triggered restart");
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ dev_info(smchid->dev, "Unknown SMC button event: %02x %02x\n", d1, d2);
|
|
+ break;
|
|
+ }
|
|
+ return NOTIFY_OK;
|
|
+ case SMC_EV_LID:
|
|
+ input_report_switch(smchid->input, SW_LID, d1);
|
|
+ input_sync(smchid->input);
|
|
+ return NOTIFY_OK;
|
|
+ }
|
|
+
|
|
+ return NOTIFY_DONE;
|
|
+}
|
|
+
|
|
+static int macsmc_hid_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct apple_smc *smc = dev_get_drvdata(pdev->dev.parent);
|
|
+ struct macsmc_hid *smchid;
|
|
+ bool have_lid, have_power;
|
|
+ int ret;
|
|
+
|
|
+ have_lid = apple_smc_key_exists(smc, SMC_KEY(MSLD));
|
|
+ have_power = apple_smc_key_exists(smc, SMC_KEY(bHLD));
|
|
+
|
|
+ if (!have_lid && !have_power)
|
|
+ return -ENODEV;
|
|
+
|
|
+ smchid = devm_kzalloc(&pdev->dev, sizeof(*smchid), GFP_KERNEL);
|
|
+ if (!smchid)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ smchid->dev = &pdev->dev;
|
|
+ smchid->smc = smc;
|
|
+
|
|
+ smchid->input = devm_input_allocate_device(&pdev->dev);
|
|
+ if (!smchid->input)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ smchid->input->phys = "macsmc-hid (0)";
|
|
+ smchid->input->name = "Apple SMC power/lid events";
|
|
+
|
|
+ if (have_lid)
|
|
+ input_set_capability(smchid->input, EV_SW, SW_LID);
|
|
+ if (have_power)
|
|
+ input_set_capability(smchid->input, EV_KEY, KEY_POWER);
|
|
+
|
|
+ ret = input_register_device(smchid->input);
|
|
+ if (ret) {
|
|
+ dev_err(&pdev->dev, "Failed to register input device: %d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (have_lid) {
|
|
+ u8 val;
|
|
+
|
|
+ ret = apple_smc_read_u8(smc, SMC_KEY(MSLD), &val);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "Failed to read initial lid state\n");
|
|
+ } else {
|
|
+ input_report_switch(smchid->input, SW_LID, val);
|
|
+ }
|
|
+ }
|
|
+ if (have_power) {
|
|
+ u32 val;
|
|
+
|
|
+ ret = apple_smc_read_u32(smc, SMC_KEY(bHLD), &val);
|
|
+ if (ret < 0) {
|
|
+ dev_err(&pdev->dev, "Failed to read initial power button state\n");
|
|
+ } else {
|
|
+ input_report_key(smchid->input, KEY_POWER, val & 1);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ input_sync(smchid->input);
|
|
+
|
|
+ smchid->nb.notifier_call = macsmc_hid_event;
|
|
+ apple_smc_register_notifier(smc, &smchid->nb);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static struct platform_driver macsmc_hid_driver = {
|
|
+ .driver = {
|
|
+ .name = "macsmc-hid",
|
|
+ },
|
|
+ .probe = macsmc_hid_probe,
|
|
+};
|
|
+module_platform_driver(macsmc_hid_driver);
|
|
+
|
|
+MODULE_AUTHOR("Hector Martin <marcan@marcan.st>");
|
|
+MODULE_LICENSE("Dual MIT/GPL");
|
|
+MODULE_DESCRIPTION("Apple SMC GPIO driver");
|
|
+MODULE_ALIAS("platform:macsmc-hid");
|
|
--
|
|
2.34.1
|
|
|