From nobody Tue Dec 16 08:59:54 2025 Received: from mail-pl1-f178.google.com (mail-pl1-f178.google.com [209.85.214.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4D5B313E21 for ; Mon, 15 Dec 2025 09:38:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765791531; cv=none; b=RT0lkuQlGDpjcoeXQ9SwqcoclPuVucQSi0IIBMkz66/JJy/YyrMYaZ1AHgCJcuoJcyZBs6TYnRfV2XpSVzFkDclYoVHMNl/ighJFR1XIucIAjMcyxxAMxEaNgfbFofUMV/ihvqEI1xjKS3uTcXrOGnRO8tQ68/FooUtLPr8Y8Jg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1765791531; c=relaxed/simple; bh=juGdkiAL8Ef7FniFZDXGGIHcDDafInr/yvVMPwDegYM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=c7ZL47mxVI4xZFFWBU56O4RjqL7pUTMt2N51MfahvG9hsUle0/FJpZYsIsyWpJfv+DA3uUhQOphmxr6l1b9GPNYPcYIda7OJmCkCnUb4GutLxW2LOMVquk2gUyHL5k/UkvrEZiZDh0tzthjlYidcE0z3xL+P0+Xc1ceeFPFoOjg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=P9T4nBai; arc=none smtp.client-ip=209.85.214.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="P9T4nBai" Received: by mail-pl1-f178.google.com with SMTP id d9443c01a7336-2a0a33d0585so12388475ad.1 for ; Mon, 15 Dec 2025 01:38:49 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1765791529; x=1766396329; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=MX4l83PZei/eA8H23B1WzGR4a5PAckpfpztaLgsdyrA=; b=P9T4nBaiHE19GitMpjDMC6krcTlbcPuD2CYpd7V4GhUxgXJ5jAiSKutKdvXSYSbwDE d9KqvMlcfYDnuwwQHkWo/+dLRSFPfneiAvIPZR/jyYqkpuQNPRdq7uuHTxqEf7TofDoJ znXyUUEzMzQzqsUzLjROwVpZ6nr0hrfvQmx4fvC1+GVijkTxOcP5vAH1xYfLBKKUZEkK HH9hNlPoO1Al080y7mXdK1IBhxvHowMgcRTPxNeiQOyx40+A9mRLMjV5qTLVNjsDRFjX kAF/I7od5uE17zeM9BfqPhZp5B3aMY2DDNhdIyTj/e+rwKJNCuYl/lGmCxSJyE44joY8 jSaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1765791529; x=1766396329; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=MX4l83PZei/eA8H23B1WzGR4a5PAckpfpztaLgsdyrA=; b=Y1WOejMvp9+CZ8Zx0PeqKygKHu/sklU6vp6lBWdJ4C2tgQRn6VBTQ1vQDFpN8tZ3mf 0Fnu/YxTNZogFTcKea8JFZ9teTjLWVKY/jtcvTePu3M5BUNBkzIXDMiEzy/cOeXFqbs4 QkeP6ZUatTeRA6ZtbR7jnxdALsoMItQFggjbZXLg6ro1npfC+e0rmfubL90r2jHsDhb5 S+ho+K4oQSpCrHhsNwm5ay4T4/M66D1dZcAluPCnnUYHGa1YIrjOTZ70+C9J4cnYtvL8 7ymIfAwaaCNzGodjdLeXlHH+/2A7QPRMfzTKMtGpf4ioCpgGe4xMrCQ78ltI8Jvfg2A4 rDLA== X-Forwarded-Encrypted: i=1; AJvYcCXquy1dsaiSubVLsc7hkOrr93hUieIpRe8o9Qra00FlRELwDfagnD+LXQGo7evNiBhahZgf7sy4V2aGmts=@vger.kernel.org X-Gm-Message-State: AOJu0YwaMclMqk3rDhTz9Rrkf2/l9VpBlZOCqXJDfcysJghzPTb6WPSW f0W0atA7V3fcTK576c9fjWIs/r0AGGneLPmxBh0JdSX/WEvIZILVYS4V6TuSWSD3 X-Gm-Gg: AY/fxX6zf7Ni7V/JFlciezIw6lXrchlXSZ3wJV3kJk5MzxhgXSu339ZYzrkMNrY0e5p 2qJ03zL9j4nZZoAA0ta4PxYL8ug5Ou4jlxXnFN8w/uB6yHe4a/7arnRYy1XBClHIhWzgKQD25AK 0N+zDl5SQXSwoHmHdXAxICFQjzgmAG0gVFblk4kSZm7NathcYm+nfpyywwqmTbBL7mWw+s/SatF W9Sbt74aiNz7lv+7yfbDn4iUgoIgRzIlO20eZvKf9C6tCPYlW3O/ZUKMKnBmUsxJG3VW8USzJxk vMrUlo3PoqXAGHRp3/ro+aRBK1f5IeOd+QXZUngr+YCYRpP3MHigvVNZyL7n6z34mWYHYONt+A/ Z6NbiTjfeN7eWutYBxgSssmHqVxwJRnkmU5bTyxuvZ569h1iKmOOd9x6BwkvXvccv/OFaApvfWB 4Kfb/BTVzi2jtL3/sZSTtpDUo98mp0kw21uoNvwG3K9g2s4hvP1fY/zHxWin50JV4GLEVStg2mt KBc6yDEDTOmpAvoyH0nlaahWaPhiZ4/8jXnzq1ehaK3asdTq2emj3GRcdR4I6XRpJYPdfyjXeYN 7eA+UmEtAu+Ixm3L0lq5o5UF/C4nYjgNg7w0N+Byn3i+fpob1MpfjeNh+MNXZw== X-Google-Smtp-Source: AGHT+IEGJ44+51Fi+YdUwyKv9dsSN+8JmzAkupuBnmxY9duLk9j4SAUpGagR8Wr9Xf65hMIh2opKeg== X-Received: by 2002:a17:902:e784:b0:295:6c26:933b with SMTP id d9443c01a7336-29f23dd1fd2mr76096885ad.1.1765791528782; Mon, 15 Dec 2025 01:38:48 -0800 (PST) Received: from [192.168.2.3] (2403-580a-80ed-0-4835-5a07-49e7-f115.ip6.aussiebb.net. [2403:580a:80ed:0:4835:5a07:49e7:f115]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-29efd74f5e1sm113017705ad.16.2025.12.15.01.38.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 15 Dec 2025 01:38:48 -0800 (PST) From: James Calligeros Date: Mon, 15 Dec 2025 19:37:48 +1000 Subject: [PATCH v6 4/7] input: macsmc-input: New driver to handle the Apple Mac SMC buttons/lid Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20251215-macsmc-subdevs-v6-4-0518cb5f28ae@gmail.com> References: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com> In-Reply-To: <20251215-macsmc-subdevs-v6-0-0518cb5f28ae@gmail.com> To: Sven Peter , Janne Grunau , Alyssa Rosenzweig , Neal Gompa , Lee Jones , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Alexandre Belloni , Jean Delvare , Guenter Roeck , Dmitry Torokhov , Jonathan Corbet , James Calligeros Cc: asahi@lists.linux.dev, linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-rtc@vger.kernel.org, linux-hwmon@vger.kernel.org, linux-input@vger.kernel.org, linux-doc@vger.kernel.org, Hector Martin X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=9128; i=jcalligeros99@gmail.com; h=from:subject:message-id; bh=lS/4q39E8TljfGLFH7Nskm9ro5EkQw4hj2XcyHKJZLk=; b=owGbwMvMwCV2xczoYuD3ygTG02pJDJn215mrpy8p3nlB5ZD90yrBuRZBLrWFR2a/lzUWjYmoi mnw3N/dMZGFQYyLwVJMkWVDk5DHbCO2m/0ilXth5rAygQyRFmlgAAIWBr7cxLxSIx0jPVNtQz1D Qx1jHSMGLk4BmGqjvQx/ZQP2h/89rBe/+7vGt6M9ATL70h0fdSodumMVxZJ/J57nGSPD+fMTtvU XTRS/uiFxg83h3Z9kX39pC41S+MVrcz54U68CFwA= X-Developer-Key: i=jcalligeros99@gmail.com; a=openpgp; fpr=B08212489B3206D98F1479BDD43632D151F77960 From: Hector Martin 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. Reviewed-by: Neal Gompa Signed-off-by: Hector Martin Co-developed-by: Sven Peter Signed-off-by: Sven Peter Signed-off-by: James Calligeros --- MAINTAINERS | 1 + drivers/input/misc/Kconfig | 11 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/macsmc-input.c | 207 +++++++++++++++++++++++++ 4 files changed, 220 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 5f160eb6762e..7f2160a18da2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2492,6 +2492,7 @@ F: drivers/hwmon/macsmc-hwmon.c F: drivers/pmdomain/apple/ F: drivers/i2c/busses/i2c-pasemi-core.c F: drivers/i2c/busses/i2c-pasemi-platform.c +F: drivers/input/misc/macsmc-input.c F: drivers/input/touchscreen/apple_z2.c F: drivers/iommu/apple-dart.c F: drivers/iommu/io-pgtable-dart.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 94a753fcb64f..0e805c870e29 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -1003,4 +1003,15 @@ config INPUT_STPMIC1_ONKEY To compile this driver as a module, choose M here: the module will be called stpmic1_onkey. =20 +config INPUT_MACSMC + tristate "Apple Mac SMC lid/buttons" + depends on MFD_MACSMC + 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-input. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 415fc4e2918b..174031304975 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222) +=3D iqs7222.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) +=3D keyspan_remote.o obj-$(CONFIG_INPUT_KXTJ9) +=3D kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) +=3D m68kspkr.o +obj-$(CONFIG_INPUT_MACSMC_INPUT) +=3D macsmc-input.o obj-$(CONFIG_INPUT_MAX7360_ROTARY) +=3D max7360-rotary.o obj-$(CONFIG_INPUT_MAX77650_ONKEY) +=3D max77650-onkey.o obj-$(CONFIG_INPUT_MAX77693_HAPTIC) +=3D max77693-haptic.o diff --git a/drivers/input/misc/macsmc-input.c b/drivers/input/misc/macsmc-= input.c new file mode 100644 index 000000000000..f4598e65fc80 --- /dev/null +++ b/drivers/input/misc/macsmc-input.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC input event driver + * Copyright The Asahi Linux Contributors + * + * This driver exposes certain events from the SMC as an input device. + * This includes the lid open/close and power button notifications. + */ + +#include +#include +#include +#include +#include + +/** + * struct macsmc_input + * @dev: Underlying struct device for the input sub-device + * @smc: Pointer to apple_smc struct of the mfd parent + * @input: Allocated input_dev; devres managed + * @nb: Notifier block used for incoming events from SMC (e.g. button pres= sed down) + * @wakeup_mode: Set to true when system is suspended and power button eve= nts should wake it + */ +struct macsmc_input { + struct device *dev; + struct apple_smc *smc; + struct input_dev *input; + struct notifier_block nb; + bool wakeup_mode; +}; + +#define SMC_EV_BTN 0x7201 +#define SMC_EV_LID 0x7203 + +#define BTN_POWER 0x01 /* power button on e.g. Mac Mini chasis pressed */ +#define BTN_TOUCHID 0x06 /* combined TouchID / power button on MacBooks p= ressed */ +#define BTN_POWER_HELD_SHORT 0xfe /* power button briefly held down */ +#define BTN_POWER_HELD_LONG 0x00 /* power button held down; sent just befo= re forced poweroff */ + +static void macsmc_input_event_button(struct macsmc_input *smcin, unsigned= long event) +{ + u8 button =3D (event >> 8) & 0xff; + u8 state =3D !!(event & 0xff); + + switch (button) { + case BTN_POWER: + case BTN_TOUCHID: + pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && state)); + + /* Suppress KEY_POWER event to prevent immediate shutdown on wake */ + if (smcin->wakeup_mode) + return; + + input_report_key(smcin->input, KEY_POWER, state); + input_sync(smcin->input); + break; + case BTN_POWER_HELD_SHORT: /* power button held down; ignore */ + break; + case BTN_POWER_HELD_LONG: + /* + * If we get here the power button has been held down for a while and + * we have about 4 seconds before forced power-off is triggered by SMC. + * Try to do an emergency shutdown to make sure the NVMe cache is + * flushed. macOS actually does this by panicing (!)... + */ + if (state) { + dev_crit(smcin->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_warn(smcin->dev, "Unknown SMC button event: %04lx\n", event & 0xffff= ); + } +} + +static void macsmc_input_event_lid(struct macsmc_input *smcin, unsigned lo= ng event) +{ + u8 lid_state =3D !!((event >> 8) & 0xff); + + pm_wakeup_dev_event(smcin->dev, 0, (smcin->wakeup_mode && !lid_state)); + input_report_switch(smcin->input, SW_LID, lid_state); + input_sync(smcin->input); +} + +static int macsmc_input_event(struct notifier_block *nb, unsigned long eve= nt, void *data) +{ + struct macsmc_input *smcin =3D container_of(nb, struct macsmc_input, nb); + u16 type =3D event >> 16; + + switch (type) { + case SMC_EV_BTN: + macsmc_input_event_button(smcin, event); + return NOTIFY_OK; + case SMC_EV_LID: + macsmc_input_event_lid(smcin, event); + return NOTIFY_OK; + default: + /* SMC event meant for another driver */ + return NOTIFY_DONE; + } +} + +static int macsmc_input_probe(struct platform_device *pdev) +{ + struct apple_smc *smc =3D dev_get_drvdata(pdev->dev.parent); + struct macsmc_input *smcin; + bool have_lid, have_power; + int error; + + /* Bail early if this SMC neither supports power button nor lid events */ + have_lid =3D apple_smc_key_exists(smc, SMC_KEY(MSLD)); + have_power =3D apple_smc_key_exists(smc, SMC_KEY(bHLD)); + if (!have_lid && !have_power) + return -ENODEV; + + smcin =3D devm_kzalloc(&pdev->dev, sizeof(*smcin), GFP_KERNEL); + if (!smcin) + return -ENOMEM; + + smcin->dev =3D &pdev->dev; + smcin->smc =3D smc; + platform_set_drvdata(pdev, smcin); + + smcin->input =3D devm_input_allocate_device(&pdev->dev); + if (!smcin->input) + return -ENOMEM; + + smcin->input->phys =3D "macsmc-input (0)"; + smcin->input->name =3D "Apple SMC power/lid events"; + + if (have_lid) + input_set_capability(smcin->input, EV_SW, SW_LID); + if (have_power) + input_set_capability(smcin->input, EV_KEY, KEY_POWER); + + if (have_lid) { + u8 val; + + error =3D apple_smc_read_u8(smc, SMC_KEY(MSLD), &val); + if (error < 0) + dev_warn(&pdev->dev, "Failed to read initial lid state\n"); + else + input_report_switch(smcin->input, SW_LID, val); + } + + if (have_power) { + u32 val; + + error =3D apple_smc_read_u32(smc, SMC_KEY(bHLD), &val); + if (error < 0) + dev_warn(&pdev->dev, "Failed to read initial power button state\n"); + else + input_report_key(smcin->input, KEY_POWER, val & 1); + } + + error =3D input_register_device(smcin->input); + if (error) { + dev_err(&pdev->dev, "Failed to register input device: %d\n", error); + return error; + } + + input_sync(smcin->input); + + smcin->nb.notifier_call =3D macsmc_input_event; + blocking_notifier_chain_register(&smc->event_handlers, &smcin->nb); + + device_init_wakeup(&pdev->dev, true); + + return 0; +} + +static int macsmc_input_pm_prepare(struct device *dev) +{ + struct macsmc_input *smcin =3D dev_get_drvdata(dev); + + smcin->wakeup_mode =3D true; + return 0; +} + +static void macsmc_input_pm_complete(struct device *dev) +{ + struct macsmc_input *smcin =3D dev_get_drvdata(dev); + + smcin->wakeup_mode =3D false; +} + +static const struct dev_pm_ops macsmc_input_pm_ops =3D { + .prepare =3D macsmc_input_pm_prepare, + .complete =3D macsmc_input_pm_complete, +}; + +static struct platform_driver macsmc_input_driver =3D { + .driver =3D { + .name =3D "macsmc-input", + .pm =3D &macsmc_input_pm_ops, + }, + .probe =3D macsmc_input_probe, +}; +module_platform_driver(macsmc_input_driver); + +MODULE_AUTHOR("Hector Martin "); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple SMC input driver"); +MODULE_ALIAS("platform:macsmc-input"); --=20 2.52.0