From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=74.125.82.182 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1793264185; b=JQ9fBe3QxO+ONP4QC95rXfeA4wvP4GU/n8HjtpP7xCc3Vq5czafg2Yo7b0zYbgdMe/aE k17T67rZtnW1JUYNt5lYiyPhDZeM13jvQlNcPVAmY4XUQqUhHdbmQms8uppJPJpx3z7qk rlCZ3wYiIj105EutGTzTpFAxduqfzCt6mPOCtFuyXjoubNF2ifgxf7yc+VUM/LnqKZTGa 4XAT6MpGf3anoWnkJHueNMrotwAQ1Afwg4n/hIlAtyKkbnZD129lCngvWuPBZAC2ubhD5 bc7te8WSi2Fx1Ud6t52qQiFLeDVwZNgdY0z+v7d7Iwv6TwVtX8cAH96gV9E2q0BclrQ== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1793264185; h=DMARC-Filter:Received:DKIM-Signature:X-Google-DKIM-Signature: X-Forwarded-Encrypted:X-Gm-Message-State:X-Gm-Gg:X-Received:Received: From:To:Cc:Subject:Date:Message-ID:X-Mailer:In-Reply-To:References: MIME-Version:Content-Transfer-Encoding; bh=AtZm1gDOBZuvZbUb1pj0nDIOnuYxC24D16xmFUaIxx8=; b=CbnYcr0QdqH3Uky1DrJ/zuaeEf2MhRUcqBEGuzsX29R/+iTbhmNrVInRm1FTX4Znk3jO RWJbxxsGIVldB9hjx0BShvMj6luNvfot56C63/krJ2CjFFy9oUpmZ+Ug3CR2LcIZxTAqp QGJBhIh0//qJ3cKj56Cioau4VfNAm74L5SROk8kbzpsj9DGEnco+JcWG1ykQbGVPp7L5h 5kHbsAemNuAllweXM16kJHuSFVBZa2dCqsEdQTrJBJBU+znQDYHEGAMCI8LhmGuvOnj4V Imc72BuQH8yHQbO6KNTgwpwXoaZCdRA7ZXj1KlC8ddeUhN5ev1x/vYKQae4RjXBiF4g== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=pjdPcamk; arc=none smtp.remote-ip=74.125.82.182 Received: from mail-dy1-f182.google.com (mail-dy1-f182.google.com [74.125.82.182]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E7D29606A32C for ; Thu, 29 Oct 2026 08:56:22 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.2 smtp.subspace.kernel.org E7D29606A32C 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, unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20260707 header.b=pjdPcamk Received: by mail-dy1-f182.google.com with SMTP id 5a478bee46e88-3514b90bb89so3478000eec.1 for ; Thu, 29 Oct 2026 01:56:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20260707; t=1793264182; x=1793868982; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=AtZm1gDOBZuvZbUb1pj0nDIOnuYxC24D16xmFUaIxx8=; b=pjdPcamk3oJ2dcWZ0HwZIrq+avI/giljD8+KRbmQkjE2omHiPp0C9p/tWguwJmIcED IC1amGEqDH0W8aniGY+Y4qScBIK0vyIscCRjoY+HXhvYQU+9NrPJ1TKwkJ/tWvChxKhG p4KoYK7OSfHfD6MMsslIOUJr4bfwSSNOzqoxWTN4KqldpTO75m0kfkMRuDJ59XTuidC0 Dv+RIrnKMMlVIuZqbchO7cw9O1veaGWIJFh5moC2+mfiGBbAHt5MD2FbkIuqOY7vNeFq hruxUXMM8oQJntFM1nVVWGLkan9pYbr737+SdQa/xG1JS8vNgZYkNHg2qVCks3XFpOzZ pJRQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1793264182; x=1793868982; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=AtZm1gDOBZuvZbUb1pj0nDIOnuYxC24D16xmFUaIxx8=; b=esZRDz02q9nXm/afoIEJ4+mloQxZJQuN0E8bZ0B4wI4GZ4U47xePh0rjCwf6F++7DK E/2JdaptTFdnIWQgyttNlfdLXrfTGHymQdFKHXfZ0JGt03DnmaH9a1qyRDoVIIv7xGJ8 Igt0ZHcIYN1fezjr6wAqyqwGm1tL/Au62aBdrVfDeG3wettn7SEVZjhR/EwKRFWBNfni F703LxneMHl+j9SPdI7GqZz9dZmfX04AgBmOXzqVkjOp/0nnIfbUZje5CKVojasT9yKw MRGisau7jTiqkKcWys640A+FB8NcEJj5XDrl4VS7QZkSnhkwntqPnhqiHg0nUH9z5JIe EnCA== X-Forwarded-Encrypted: i=1; AKwUvByZCOtwC+LfzI6AHRz0F/NGIhlze9c35yI1lJI4e3TLdhT3kGzEXeT2T3z61WChBcGh7UNznPIrnd0gOpI=@vger.kernel.org X-Gm-Message-State: AFq9FYK/hdGJcoG8dYvLd6Vea7dU/RE1ZrUfHRNjO9n6t+tK/tg72+jW Ns39a1Y8MJtXzjs5RpG5bC+3Oin2qiHk6tUJoAynE6qe7tEGhKtGsO8= X-Gm-Gg: AYBFou2DUURUe3BnoaBAVuzppak+psI4XKV+dJAXMoPPPQBTOmHiigdCu27WCKkIlq9 YBQt6sXK+pP1IJKfwV4EeyH6wdhS6KPQuQMYFfBRT3QzA1aLRut2HTkbYldg2KBlrixyYUPNDr2 d+79IrBOcJ+YNgrDj6RsFKS+fZsLWGnNpaZSvgU74dCHx6CzfPLJAlL6JnvKTT4VCedx5mqrzjW X8tslGgyz30KpQ0hD9GEthGSlTQFX/bs0vINdt3Vr8J3q8oSnQvRVcvbtgKoMWrgR5Naodfuy88 MRRvrhT8bHGZVkySdlLVL2MgmiKGSxUxmF6CXFMMViuahA/guktpgZVoaL3CNa6QQ12zSEVonpI VoE0EPD1rnoh1D6EE0VOdcfBmk0qKemgKCUDjKldOfOt70BMfLpJq3dee1fXo5RkKWPEdryOmFe 7GjQY9UZAbt+G0bt6phVOdeWby/Qvn6yFvUQXEVKKBtmIkWFr9aI/MdMapWw703mB6HzZB+j5+a PAVg7KQoFLz37eyJgdPuEXYZwIayBWAvQAHUgSmXJhNmUrxil9/3JPjKwmuGQp4YW7z1US8XlZv Q/IJWhGqMdQhNe/xMcdv+t8nExxp1jdzxWrACOG5FgTy1hDLD/cd8nIytT7k9A== X-Received: by 2002:a05:7301:b09:b0:360:d4c5:7243 with SMTP id 5a478bee46e88-36a2002d2cfmr6080079eec.11.1793264181667; Thu, 29 Oct 2026 01:56:21 -0700 (PDT) Received: from at-Standard-PC-Q35-ICH9-2009 ([27.60.20.232]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-36a23641e78sm16497937eec.0.2026.10.29.01.56.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 29 Oct 2026 01:56:21 -0700 (PDT) From: Atharva Tiwari To: Cc: Atharva Tiwari , Bjorn Helgaas , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , "Rafael J. Wysocki" , Len Brown , Linus Walleij , Bartosz Golaszewski , Sven Peter , Janne Grunau , Neal Gompa , Guenter Roeck , Jonathan Cameron , David Lechner , =?UTF-8?q?Nuno=20S=C3=A1?= , Andy Shevchenko , Lee Jones , Pavel Machek , Griffin Kroah-Hartman , Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= , Sebastian Reichel , Alexandre Belloni , Wim Van Sebroeck , Jarkko Sakkinen , Mimi Zohar , Roberto Sassu , Dmitry Kasatkin , Eric Snowberg , Paul Moore , James Morris , "Serge E. Hallyn" , linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, linux-acpi@vger.kernel.org, linux-gpio@vger.kernel.org, asahi@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-hwmon@vger.kernel.org, linux-iio@vger.kernel.org, linux-leds@vger.kernel.org, mfd@lists.linux.dev, platform-driver-x86@vger.kernel.org, linux-pm@vger.kernel.org, linux-rtc@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-integrity@vger.kernel.org, keyrings@vger.kernel.org, linux-security-module@vger.kernel.org Subject: [RFC PATCH 01/14] treewide: Add backend for macsmc Date: Thu, 29 Oct 2026 04:51:58 -0400 Message-ID: <20261029085504.3547-2-atharvatiwarilinuxdev@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20261029085504.3547-1-atharvatiwarilinuxdev@gmail.com> References: <20261029085504.3547-1-atharvatiwarilinuxdev@gmail.com> X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Split the Apple SMC driver into a common core and a backend that handles the actual communication. The existing RTKit code moves to its own backend, and nothing changes for Apple Silicon. This lets the same SMC drivers run on other kinds of hardware, starting with Intel Macs, as a replacement for applesmc. Signed-off-by: Atharva Tiwari --- MAINTAINERS | 2 +- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-macsmc.c | 13 +- drivers/hwmon/Kconfig | 2 +- drivers/mfd/Kconfig | 15 +- drivers/mfd/Makefile | 2 +- drivers/mfd/macsmc-core.c | 164 ++++++++++++++++ drivers/power/reset/Kconfig | 2 +- drivers/power/supply/Kconfig | 2 +- drivers/power/supply/macsmc-power.c | 4 +- drivers/rtc/Kconfig | 2 +- drivers/soc/apple/Kconfig | 14 ++ drivers/soc/apple/Makefile | 2 + .../macsmc.c => soc/apple/macsmc-rtkit.c} | 185 ++++++++---------- include/linux/mfd/macsmc.h | 81 +++++--- 15 files changed, 326 insertions(+), 166 deletions(-) create mode 100644 drivers/mfd/macsmc-core.c rename drivers/{mfd/macsmc.c => soc/apple/macsmc-rtkit.c} (70%) diff --git a/MAINTAINERS b/MAINTAINERS index 03649f08c..1e5ae12ce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2727,7 +2727,7 @@ F: drivers/input/touchscreen/apple_z2.c F: drivers/iommu/apple-dart.c F: drivers/iommu/io-pgtable-dart.c F: drivers/irqchip/irq-apple-aic.c -F: drivers/mfd/macsmc.c +F: drivers/mfd/macsmc-core.c F: drivers/nvme/host/apple.c F: drivers/nvmem/apple-efuses.c F: drivers/nvmem/apple-spmi-nvmem.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 55e428002..63a2b1e2e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1582,7 +1582,7 @@ config GPIO_LP87565 config GPIO_MACSMC tristate "Apple Mac SMC GPIO" - depends on MFD_MACSMC + depends on MACSMC_RTKIT help Support for GPIOs controlled by the SMC microcontroller on Apple Mac systems. diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c index b0952d066..8c7a942ad 100644 --- a/drivers/gpio/gpio-macsmc.c +++ b/drivers/gpio/gpio-macsmc.c @@ -97,20 +97,9 @@ static int macsmc_gpio_find_first_gpio_index(struct macsmc_gpio *smcgp) { struct apple_smc *smc = smcgp->smc; smc_key key = macsmc_gpio_key(0); - smc_key first_key, last_key; int start, count, ret; - /* Return early if the key is out of bounds */ - ret = apple_smc_get_key_by_index(smc, 0, &first_key); - if (ret) - return ret; - if (key <= first_key) - return -ENODEV; - - ret = apple_smc_get_key_by_index(smc, smc->key_count - 1, &last_key); - if (ret) - return ret; - if (key > last_key) + if (key <= smc->first_key || key > smc->last_key) return -ENODEV; /* Binary search to find index of first SMC key bigger or equal to key */ diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 18c682e1a..91ca7031c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1245,7 +1245,7 @@ config SENSORS_LTQ_CPUTEMP config SENSORS_MACSMC_HWMON tristate "Apple SMC (Apple Silicon)" - depends on MFD_MACSMC && OF + depends on MFD_MACSMC_CORE help This driver enables hwmon support for current, power, temperature, and voltage sensors, as well as fan speed reporting and control diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 87ed55c15..c58cc3315 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -339,24 +339,15 @@ config MFD_LOCHNAGAR help Support for Cirrus Logic Lochnagar audio development board. -config MFD_MACSMC - tristate "Apple Silicon System Management Controller (SMC)" - depends on ARCH_APPLE || COMPILE_TEST - depends on OF - depends on APPLE_RTKIT +config MFD_MACSMC_CORE + tristate "Apple System Management Controller (SMC) Core" select MFD_CORE help - The System Management Controller (SMC) on Apple Silicon machines is a + The System Management Controller (SMC) on Apple machines is a piece of hardware that exposes various functionalities such as temperature sensors, voltage/power meters, shutdown/reboot handling, GPIOs and more. - Communication happens via a shared mailbox using the RTKit protocol - which is also used for other co-processors. The SMC protocol then - allows reading and writing many different keys which implement the - various features. The MFD core device handles this protocol and - exposes it to the sub-devices. - config MFD_MADERA tristate "Cirrus Logic Madera codecs" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index f8101d2a9..0b0ccf91e 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_MFD_CS42L43_SDW) += cs42l43-sdw.o obj-$(CONFIG_MFD_ENE_KB3930) += ene-kb3930.o obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o obj-$(CONFIG_MFD_GATEWORKS_GSC) += gateworks-gsc.o -obj-$(CONFIG_MFD_MACSMC) += macsmc.o +obj-$(CONFIG_MFD_MACSMC_CORE) += macsmc-core.o obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o obj-$(CONFIG_MFD_TI_LP87565) += lp87565.o diff --git a/drivers/mfd/macsmc-core.c b/drivers/mfd/macsmc-core.c new file mode 100644 index 000000000..b8905c834 --- /dev/null +++ b/drivers/mfd/macsmc-core.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SMC core framework + * Copyright (C) 2026 Atharva Tiwari + */ + +#include +#include +#include +#include +#include +#include + +static const struct mfd_cell apple_smc_rtkit_devs[] = { + MFD_CELL_NAME("macsmc-input"), + MFD_CELL_NAME("macsmc-power"), + MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"), + MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), + MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), + MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"), +}; + +/* + * There isn't device tree on acpi backend, so we need to use + * apple_smc_key_exists to register mfd devs + */ +static const struct mfd_cell apple_smc_acpi_common[] = { + MFD_CELL_NAME("macsmc-hwmon"), + MFD_CELL_NAME("macsmc-power"), +}; + +static const struct mfd_cell apple_smc_acpi_rtc[] = { + MFD_CELL_NAME("macsmc-rtc"), +}; + +int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size) +{ + guard(mutex)(&smc->mutex); + return smc->be->read(smc->be_cookie, key, buf, size); +} +EXPORT_SYMBOL(apple_smc_read); + +int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size) +{ + guard(mutex)(&smc->mutex); + return smc->be->write(smc->be_cookie, key, buf, size); +} +EXPORT_SYMBOL(apple_smc_write); + +int apple_smc_enter_atomic(struct apple_smc *smc) +{ + guard(mutex)(&smc->mutex); + return smc->be->enter_atomic(smc->be_cookie); +} +EXPORT_SYMBOL(apple_smc_enter_atomic); + +int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size) +{ + guard(spinlock_irqsave)(&smc->lock); + return smc->be->write_atomic(smc->be_cookie, key, buf, size); +} +EXPORT_SYMBOL(apple_smc_write_atomic); + +int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize, + void *rbuf, size_t rsize) +{ + guard(mutex)(&smc->mutex); + return smc->be->rw(smc->be_cookie, key, wbuf, wsize, rbuf, rsize); +} +EXPORT_SYMBOL(apple_smc_rw); + +int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key) +{ + guard(mutex)(&smc->mutex); + int ret; + + ret = smc->be->get_key_by_index(smc->be_cookie, index, key); + *key = swab32(*key); + + return ret; +} +EXPORT_SYMBOL(apple_smc_get_key_by_index); + +int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info) +{ + guard(mutex)(&smc->mutex); + return smc->be->get_key_info(smc->be_cookie, key, info); +} +EXPORT_SYMBOL(apple_smc_get_key_info); + +static void apple_smc_disable_notifications(void *data) +{ + struct apple_smc *smc = data; + + guard(mutex)(&smc->mutex); + smc->be->disable_notifications(smc->be_cookie); +} + +int apple_smc_probe(struct device *dev, const struct apple_smc_backend_ops *ops, + void *cookie, struct blocking_notifier_head *event_handlers, bool is_acpi) +{ + struct apple_smc *smc; + __be32 count; + int ret; + + smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL); + if (!smc) + return -ENOMEM; + + smc->dev = dev; + smc->be_cookie = cookie; + smc->be = ops; + smc->is_acpi = is_acpi; + smc->event_handlers = event_handlers; + mutex_init(&smc->mutex); + spin_lock_init(&smc->lock); + + ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count); + if (ret < 0) + return ret; + smc->key_count = be32_to_cpu(count); + + ret = apple_smc_get_key_by_index(smc, 0, &smc->first_key); + if (ret < 0) + return ret; + + ret = apple_smc_get_key_by_index(smc, smc->key_count - 1, &smc->last_key); + if (ret < 0) + return ret; + + dev_set_drvdata(dev, smc); + + ret = devm_add_action_or_reset(dev, apple_smc_disable_notifications, smc); + if (ret) + return ret; + + if (smc->is_acpi) { + ret = devm_mfd_add_devices(dev, -1, apple_smc_acpi_common, + ARRAY_SIZE(apple_smc_acpi_common), NULL, 0, NULL); + if (ret < 0) + return ret; + + if (apple_smc_key_exists(smc, SMC_KEY(CLKO))) { + ret = devm_mfd_add_devices(dev, -1, apple_smc_acpi_rtc, + ARRAY_SIZE(apple_smc_acpi_rtc), NULL, 0, NULL); + if (ret < 0) + return ret; + } + + } else + ret = devm_mfd_add_devices(dev, -1, apple_smc_rtkit_devs, + ARRAY_SIZE(apple_smc_rtkit_devs), NULL, 0, NULL); + if (ret < 0) + return ret; + + dev_info(dev, "Successfully Initialized (%d keys First key: %p4ch Last key: %p4ch)\n", + smc->key_count, &smc->first_key, &smc->last_key); + return 0; +} +EXPORT_SYMBOL(apple_smc_probe); + +MODULE_AUTHOR("Atharva Tiwari "); +MODULE_LICENSE("Dual MIT/GPL"); +MODULE_DESCRIPTION("Apple SMC core"); diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index bce996bbe..14d62afc1 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -142,7 +142,7 @@ config POWER_RESET_MCF_RCM config POWER_RESET_MACSMC tristate "Apple SMC reset/power-off driver" - depends on MFD_MACSMC + depends on MACSMC_RTKIT help This driver supports reset and power-off on Apple Mac machines that implement this functionality via the SMC. diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index b89ef40df..6e944cc59 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -1193,7 +1193,7 @@ config FUEL_GAUGE_MM8013 config MACSMC_POWER tristate "Apple SMC Battery and Power Driver" - depends on MFD_MACSMC + depends on MFD_MACSMC_CORE help This driver provides support for the battery and AC adapter on Apple Silicon machines. It exposes battery telemetry (voltage, diff --git a/drivers/power/supply/macsmc-power.c b/drivers/power/supply/macsmc-power.c index ef735f863..ced37a701 100644 --- a/drivers/power/supply/macsmc-power.c +++ b/drivers/power/supply/macsmc-power.c @@ -859,7 +859,7 @@ static int macsmc_power_probe(struct platform_device *pdev) return -ENODEV; power->nb.notifier_call = macsmc_power_event; - blocking_notifier_chain_register(&smc->event_handlers, &power->nb); + blocking_notifier_chain_register(smc->event_handlers, &power->nb); return 0; } @@ -868,7 +868,7 @@ static void macsmc_power_remove(struct platform_device *pdev) { struct macsmc_power *power = dev_get_drvdata(&pdev->dev); - blocking_notifier_chain_unregister(&power->smc->event_handlers, &power->nb); + blocking_notifier_chain_unregister(power->smc->event_handlers, &power->nb); } static const struct platform_device_id macsmc_power_id[] = { diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 05b9233b9..8cc27891b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -2096,7 +2096,7 @@ config RTC_DRV_WILCO_EC config RTC_DRV_MACSMC tristate "Apple Mac System Management Controller RTC" - depends on MFD_MACSMC + depends on MFD_MACSMC_CORE help If you say yes here you get support for RTC functions inside Apple SPMI PMUs accessed through the SoC's diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index db30c0ade..e89bc9cb4 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -52,6 +52,20 @@ config APPLE_TUNABLE tristate depends on ARCH_APPLE || COMPILE_TEST +config MACSMC_RTKIT + tristate "Apple Silicon System Management Controller (SMC) Backend" + depends on ARCH_APPLE || COMPILE_TEST + depends on OF + depends on APPLE_RTKIT + depends on MFD_MACSMC_CORE + help + MACSMC RTKIT allows communicatation with the System Management + Controller on M-series Macs. It is required to use GPIO, control fans + and to control battery start and end threshold. + + Say 'y' here if you have an Apple Soc + + endmenu endif diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile index 0481f7f43..7227cf69e 100644 --- a/drivers/soc/apple/Makefile +++ b/drivers/soc/apple/Makefile @@ -13,3 +13,5 @@ apple-sart-y = sart.o obj-$(CONFIG_APPLE_TUNABLE) += apple-tunable.o apple-tunable-y = tunable.o + +obj-$(CONFIG_MACSMC_RTKIT) += macsmc-rtkit.o diff --git a/drivers/mfd/macsmc.c b/drivers/soc/apple/macsmc-rtkit.c similarity index 70% rename from drivers/mfd/macsmc.c rename to drivers/soc/apple/macsmc-rtkit.c index 514cba7dc..eaebeb1be 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/soc/apple/macsmc-rtkit.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -27,14 +26,6 @@ #define SMC_SHMEM_SIZE 0x1000 #define SMC_MAX_SIZE 255 -#define SMC_MSG_READ_KEY 0x10 -#define SMC_MSG_WRITE_KEY 0x11 -#define SMC_MSG_GET_KEY_BY_INDEX 0x12 -#define SMC_MSG_GET_KEY_INFO 0x13 -#define SMC_MSG_INITIALIZE 0x17 -#define SMC_MSG_NOTIFICATION 0x18 -#define SMC_MSG_RW_KEY 0x20 - #define SMC_DATA GENMASK_ULL(63, 32) #define SMC_WSIZE GENMASK_ULL(31, 24) #define SMC_SIZE GENMASK_ULL(23, 16) @@ -44,24 +35,35 @@ #define SMC_TIMEOUT_MS 500 -static const struct mfd_cell apple_smc_devs[] = { - MFD_CELL_NAME("macsmc-input"), - MFD_CELL_NAME("macsmc-power"), - MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"), - MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), - MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"), - MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"), +struct apple_smc_rtkit { + struct device *dev; + + struct blocking_notifier_head event_handlers; + + struct apple_rtkit *rtk; + + struct completion init_done; + enum apple_smc_boot_stage boot_stage; + + struct resource *sram; + void __iomem *sram_base; + struct apple_rtkit_shmem shmem; + + unsigned int msg_id; + + bool atomic_mode; + bool atomic_pending; + struct completion cmd_done; + u64 cmd_ret; }; -static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg, +static int apple_smc_rtkit_cmd_locked(struct apple_smc_rtkit *smc, u64 cmd, u64 arg, u64 size, u64 wsize, u32 *ret_data) { u8 result; int ret; u64 msg; - lockdep_assert_held(&smc->mutex); - if (smc->boot_stage != APPLE_SMC_INITIALIZED) return -EIO; if (smc->atomic_mode) @@ -103,15 +105,7 @@ static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg, return FIELD_GET(SMC_SIZE, smc->cmd_ret); } -static int apple_smc_cmd(struct apple_smc *smc, u64 cmd, u64 arg, - u64 size, u64 wsize, u32 *ret_data) -{ - guard(mutex)(&smc->mutex); - - return apple_smc_cmd_locked(smc, cmd, arg, size, wsize, ret_data); -} - -static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key, +static int apple_smc_rtkit_rw_locked(struct apple_smc_rtkit *smc, smc_key key, const void *wbuf, size_t wsize, void *rbuf, size_t rsize) { @@ -120,8 +114,6 @@ static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key, int ret; u64 cmd; - lockdep_assert_held(&smc->mutex); - if (rsize > SMC_MAX_SIZE) return -EINVAL; if (wsize > SMC_MAX_SIZE) @@ -149,7 +141,7 @@ static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key, return -EINVAL; } - ret = apple_smc_cmd_locked(smc, cmd, key, smc_size, smc_wsize, &rdata); + ret = apple_smc_rtkit_cmd_locked(smc, cmd, key, smc_size, smc_wsize, &rdata); if (ret < 0) return ret; @@ -169,48 +161,42 @@ static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key, return ret; } -int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size) +static int apple_smc_rtkit_read(void *cookie, smc_key key, void *buf, size_t size) { - guard(mutex)(&smc->mutex); + struct apple_smc_rtkit *smc = cookie; - return apple_smc_rw_locked(smc, key, NULL, 0, buf, size); + return apple_smc_rtkit_rw_locked(smc, key, NULL, 0, buf, size); } -EXPORT_SYMBOL(apple_smc_read); -int apple_smc_write(struct apple_smc *smc, smc_key key, const void *buf, size_t size) +static int apple_smc_rtkit_write(void *cookie, smc_key key, const void *buf, size_t size) { - guard(mutex)(&smc->mutex); + struct apple_smc_rtkit *smc = cookie; - return apple_smc_rw_locked(smc, key, buf, size, NULL, 0); + return apple_smc_rtkit_rw_locked(smc, key, buf, size, NULL, 0); } -EXPORT_SYMBOL(apple_smc_write); -int apple_smc_rw(struct apple_smc *smc, smc_key key, const void *wbuf, size_t wsize, +static int apple_smc_rtkit_rw(void *cookie, smc_key key, const void *wbuf, size_t wsize, void *rbuf, size_t rsize) { - guard(mutex)(&smc->mutex); + struct apple_smc_rtkit *smc = cookie; - return apple_smc_rw_locked(smc, key, wbuf, wsize, rbuf, rsize); + return apple_smc_rtkit_rw_locked(smc, key, wbuf, wsize, rbuf, rsize); } -EXPORT_SYMBOL(apple_smc_rw); -int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key) +static int apple_smc_rtkit_get_key_by_index(void *cookie, int index, smc_key *key) { - int ret; + struct apple_smc_rtkit *smc = cookie; - ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_BY_INDEX, index, 0, 0, key); - - *key = swab32(*key); - return ret; + return apple_smc_rtkit_cmd_locked(smc, SMC_MSG_GET_KEY_BY_INDEX, index, 0, 0, key); } -EXPORT_SYMBOL(apple_smc_get_key_by_index); -int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info) +static int apple_smc_rtkit_get_key_info(void *cookie, smc_key key, struct apple_smc_key_info *info) { + struct apple_smc_rtkit *smc = cookie; u8 key_info[6]; int ret; - ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_INFO, key, 0, 0, NULL); + ret = apple_smc_rtkit_cmd_locked(smc, SMC_MSG_GET_KEY_INFO, key, 0, 0, NULL); if (ret >= 0 && info) { memcpy_fromio(key_info, smc->shmem.iomem, sizeof(key_info)); info->size = key_info[0]; @@ -219,12 +205,9 @@ int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_ } return ret; } -EXPORT_SYMBOL(apple_smc_get_key_info); -int apple_smc_enter_atomic(struct apple_smc *smc) +static int apple_smc_rtkit_enter_atomic(void *cookie) { - guard(mutex)(&smc->mutex); - /* * Disable notifications since this is called before shutdown and no * notification handler will be able to handle the notification @@ -233,19 +216,19 @@ int apple_smc_enter_atomic(struct apple_smc *smc) * We can't use apple_smc_write_flag here since that would try to lock * smc->mutex again. */ + struct apple_smc_rtkit *smc = cookie; const u8 flag = 0; - apple_smc_rw_locked(smc, SMC_KEY(NTAP), &flag, sizeof(flag), NULL, 0); + apple_smc_rtkit_rw_locked(smc, SMC_KEY(NTAP), &flag, sizeof(flag), NULL, 0); smc->atomic_mode = true; return 0; } -EXPORT_SYMBOL(apple_smc_enter_atomic); -int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, size_t size) +static int apple_smc_rtkit_write_atomic(void *cookie, smc_key key, const void *buf, size_t size) { - guard(spinlock_irqsave)(&smc->lock); + struct apple_smc_rtkit *smc = cookie; u8 result; int ret; u64 msg; @@ -293,11 +276,28 @@ int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, const void *buf, return FIELD_GET(SMC_SIZE, smc->cmd_ret); } -EXPORT_SYMBOL(apple_smc_write_atomic); + +static void apple_smc_rtkit_disable_notifications(void *cookie) +{ + const u8 flag = 0; + + apple_smc_rtkit_write(cookie, SMC_KEY(NTAP), &flag, sizeof(flag)); +} + +static const struct apple_smc_backend_ops apple_smc_rtkit_backend_ops = { + .read = apple_smc_rtkit_read, + .write = apple_smc_rtkit_write, + .enter_atomic = apple_smc_rtkit_enter_atomic, + .write_atomic = apple_smc_rtkit_write_atomic, + .rw = apple_smc_rtkit_rw, + .get_key_by_index = apple_smc_rtkit_get_key_by_index, + .get_key_info = apple_smc_rtkit_get_key_info, + .disable_notifications = apple_smc_rtkit_disable_notifications, +}; static void apple_smc_rtkit_crashed(void *cookie, const void *bfr, size_t bfr_len) { - struct apple_smc *smc = cookie; + struct apple_smc_rtkit *smc = cookie; smc->boot_stage = APPLE_SMC_ERROR_CRASHED; dev_err(smc->dev, "SMC crashed! Your system will reboot in a few seconds...\n"); @@ -305,7 +305,7 @@ static void apple_smc_rtkit_crashed(void *cookie, const void *bfr, size_t bfr_le static int apple_smc_rtkit_shmem_setup(void *cookie, struct apple_rtkit_shmem *bfr) { - struct apple_smc *smc = cookie; + struct apple_smc_rtkit *smc = cookie; size_t bfr_end; if (!bfr->iova) { @@ -332,7 +332,7 @@ static int apple_smc_rtkit_shmem_setup(void *cookie, struct apple_rtkit_shmem *b static bool apple_smc_rtkit_recv_early(void *cookie, u8 endpoint, u64 message) { - struct apple_smc *smc = cookie; + struct apple_smc_rtkit *smc = cookie; if (endpoint != SMC_ENDPOINT) { dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); @@ -368,7 +368,7 @@ static bool apple_smc_rtkit_recv_early(void *cookie, u8 endpoint, u64 message) static void apple_smc_rtkit_recv(void *cookie, u8 endpoint, u64 message) { - struct apple_smc *smc = cookie; + struct apple_smc_rtkit *smc = cookie; if (endpoint != SMC_ENDPOINT) { dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); @@ -392,32 +392,24 @@ static const struct apple_rtkit_ops apple_smc_rtkit_ops = { static void apple_smc_rtkit_shutdown(void *data) { - struct apple_smc *smc = data; + struct apple_smc_rtkit *smc = data; /* Shut down SMC firmware, if it's not completely wedged */ if (apple_rtkit_is_running(smc->rtk)) apple_rtkit_quiesce(smc->rtk); } -static void apple_smc_disable_notifications(void *data) -{ - struct apple_smc *smc = data; - - apple_smc_write_flag(smc, SMC_KEY(NTAP), false); -} - -static int apple_smc_probe(struct platform_device *pdev) +static int apple_smc_rtkit_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct apple_smc *smc; - __be32 count; + struct apple_smc_rtkit *smc; + const u8 flag = 1; int ret; smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL); if (!smc) return -ENOMEM; - mutex_init(&smc->mutex); smc->dev = &pdev->dev; smc->sram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &smc->sram); if (IS_ERR(smc->sram_base)) @@ -458,49 +450,32 @@ static int apple_smc_probe(struct platform_device *pdev) return -EIO; } - dev_set_drvdata(&pdev->dev, smc); BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers); - ret = apple_smc_read(smc, SMC_KEY(#KEY), &count, sizeof(count)); - if (ret >= 0 && ret != sizeof(count)) - ret = -EINVAL; - if (ret < 0) - return dev_err_probe(smc->dev, ret, "Failed to get key count"); - smc->key_count = be32_to_cpu(count); - /* Enable notifications */ - apple_smc_write_flag(smc, SMC_KEY(NTAP), true); - ret = devm_add_action_or_reset(dev, apple_smc_disable_notifications, smc); - if (ret) - return ret; + apple_smc_rtkit_rw_locked(smc, SMC_KEY(NTAP), &flag, sizeof(flag), NULL, 0); - ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, - apple_smc_devs, ARRAY_SIZE(apple_smc_devs), - NULL, 0, NULL); - if (ret) - return dev_err_probe(smc->dev, ret, "Failed to register sub-devices"); - - - return 0; + return apple_smc_probe(dev, &apple_smc_rtkit_backend_ops, smc, + &smc->event_handlers, false); } -static const struct of_device_id apple_smc_of_match[] = { +static const struct of_device_id apple_smc_rtkit_of_match[] = { { .compatible = "apple,t8103-smc" }, { .compatible = "apple,smc" }, {}, }; -MODULE_DEVICE_TABLE(of, apple_smc_of_match); +MODULE_DEVICE_TABLE(of, apple_smc_rtkit_of_match); -static struct platform_driver apple_smc_driver = { +static struct platform_driver apple_smc_rtkit_driver = { .driver = { - .name = "macsmc", - .of_match_table = apple_smc_of_match, + .name = "macsmc-rtkit", + .of_match_table = apple_smc_rtkit_of_match, }, - .probe = apple_smc_probe, + .probe = apple_smc_rtkit_probe, }; -module_platform_driver(apple_smc_driver); +module_platform_driver(apple_smc_rtkit_driver); MODULE_AUTHOR("Hector Martin "); MODULE_AUTHOR("Sven Peter "); MODULE_LICENSE("Dual MIT/GPL"); -MODULE_DESCRIPTION("Apple SMC driver"); +MODULE_DESCRIPTION("Apple SMC RTKIT Backend driver"); diff --git a/include/linux/mfd/macsmc.h b/include/linux/mfd/macsmc.h index cc09ecce0..4b4368b99 100644 --- a/include/linux/mfd/macsmc.h +++ b/include/linux/mfd/macsmc.h @@ -47,6 +47,14 @@ typedef u32 smc_key; #define APPLE_SMC_WRITABLE BIT(6) #define APPLE_SMC_FUNCTION BIT(4) +#define SMC_MSG_READ_KEY 0x10 +#define SMC_MSG_WRITE_KEY 0x11 +#define SMC_MSG_GET_KEY_BY_INDEX 0x12 +#define SMC_MSG_GET_KEY_INFO 0x13 +#define SMC_MSG_INITIALIZE 0x17 +#define SMC_MSG_NOTIFICATION 0x18 +#define SMC_MSG_RW_KEY 0x20 + /** * struct apple_smc_key_info - Information for a SMC key as returned by SMC * @type_code: FourCC code indicating the type for this key. @@ -80,24 +88,41 @@ enum apple_smc_boot_stage { APPLE_SMC_ERROR_CRASHED }; +/** + * struct apple_smc_backend_ops - SMC backend interface + * @read: Read SMC key data + * @write: Write SMC key data + * @enter_atomic: Enter atomic access mode + * @write_atomic: Atomic write to SMC key + * @rw: Combined write/read transaction + * @get_key_by_index: Resolve key by index + * @get_key_info: Get metadata for key + * @disable_notifications: Disable notfications on removal + */ +struct apple_smc_backend_ops { + int (*read)(void *cookie, smc_key key, void *buf, size_t size); + int (*write)(void *cookie, smc_key key, const void *buf, size_t size); + int (*enter_atomic)(void *cookie); + int (*write_atomic)(void *cookie, smc_key key, const void *buf, size_t size); + int (*rw)(void *cookie, smc_key key, const void *wbuf, size_t wsize, + void *rbuf, size_t rsize); + int (*get_key_by_index)(void *cookie, int index, smc_key *key); + int (*get_key_info)(void *cookie, smc_key key, + struct apple_smc_key_info *info); + void (*disable_notifications)(void *cookie); +}; + + /** * struct apple_smc * @dev: Underlying device struct for the physical backend device * @key_count: Number of available SMC keys * @first_key: First valid SMC key * @last_key: Last valid SMC key - * @event_handlers: Notifier call chain for events received from SMC - * @rtk: Pointer to Apple RTKit instance - * @init_done: Completion for initialization - * @boot_stage: Current boot stage of SMC - * @sram: Pointer to SRAM resource - * @sram_base: SRAM base address - * @shmem: RTKit shared memory structure for SRAM - * @msg_id: Current message id for commands, will be incremented for each command - * @atomic_mode: Flag set when atomic mode is entered - * @atomic_pending: Flag indicating pending atomic command - * @cmd_done: Completion for command execution in non-atomic mode - * @cmd_ret: Return value from SMC for last command + * @event_handlers: Pointer to Notifier call chain from the backend + * @be: Backend operations for SMC access + * @be_cookie: Backend context passed to ops callbacks + * @is_acpi: Is the backend ACPI based * @mutex: Mutex for non-atomic mode * @lock: Spinlock for atomic mode */ @@ -108,23 +133,11 @@ struct apple_smc { smc_key first_key; smc_key last_key; - struct blocking_notifier_head event_handlers; - - struct apple_rtkit *rtk; + struct blocking_notifier_head *event_handlers; + const struct apple_smc_backend_ops *be; + void *be_cookie; - struct completion init_done; - enum apple_smc_boot_stage boot_stage; - - struct resource *sram; - void __iomem *sram_base; - struct apple_rtkit_shmem shmem; - - unsigned int msg_id; - - bool atomic_mode; - bool atomic_pending; - struct completion cmd_done; - u64 cmd_ret; + bool is_acpi; struct mutex mutex; spinlock_t lock; @@ -225,6 +238,18 @@ static inline bool apple_smc_key_exists(struct apple_smc *smc, smc_key key) return apple_smc_get_key_info(smc, key, NULL) >= 0; } +/** + * apple_smc_probe - Initialize Apple SMC device + * @dev: Device for the SMC instance + * @ops: Backend operations for SMC access + * @cookie: Opaque backend context + * @event_handlers: Pointer to Notifier call chain from backend + * @is_acpi: Is the backend ACPI based. + * Return: Zero on success, negative errno on error + */ +int apple_smc_probe(struct device *dev, const struct apple_smc_backend_ops *ops, + void *cookie, struct blocking_notifier_head *event_handlers, bool is_acpi); + #define APPLE_SMC_TYPE_OPS(type) \ static inline int apple_smc_read_##type(struct apple_smc *smc, smc_key key, type *p) \ { \ -- 2.55.0