summaryrefslogtreecommitdiffstats
path: root/drivers/mfd/ab8500-sysctrl.c
diff options
context:
space:
mode:
authorMiguel Ojeda <ojeda@kernel.org>2026-08-16 15:32:33 +0200
committerMiguel Ojeda <ojeda@kernel.org>2026-08-23 21:27:17 +0200
commit5febf432df1cfa5b25d99b54c32103fafbdd0eb9 (patch)
tree93a1ed1d337bc53adf1e572c2586d347703b286e /drivers/mfd/ab8500-sysctrl.c
downloadlinux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.tar.gz
linux-stable-5febf432df1cfa5b25d99b54c32103fafbdd0eb9.zip
kbuild: rust: keep Rust objects out of Clang LTO with inline helpersgrafted
Under `CONFIG_LTO_CLANG` + `CONFIG_RUST_INLINE_HELPERS`, one may hit `objtool` errors such as: vmlinux.o: error: objtool: _R..._3Gsp4boot+0xd6a: can't find jump dest instruction at .text._R..._3Gsp4boot+0x1dfd The reason is that in such builds, the Clang invocation that compiles the combined Rust plus helpers bitcode emits LLVM bitcode (again) -- the final code generation happens in the linker's LTO step, which the `-mllvm` trap options passed to Clang do not reach. This, in turn, means that unreachable traps are missing, and the impossible paths do not merely fallthrough to the next symbol, but past the end of their own section, since LTO builds place each function in its own section. Thus filter `CC_FLAGS_LTO` out of the Clang invocation, so that it always emits machine code directly, with the traps in place. Assisted-by: LLM Cc: Gary Guo <gary@garyguo.net> Cc: Boqun Feng <boqun@kernel.org> Cc: Alice Ryhl <aliceryhl@google.com> Cc: Matthew Maurer <mmaurer@google.com> Cc: Josh Poimboeuf <jpoimboe@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: stable@vger.kernel.org Fixes: 3a2486cc1da5 ("kbuild: rust: provide an option to inline C helpers into Rust") Acked-by: Gary Guo <gary@garyguo.net> Link: https://patch.msgid.link/20260816133233.197500-2-ojeda@kernel.org Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Diffstat (limited to 'drivers/mfd/ab8500-sysctrl.c')
-rw-r--r--drivers/mfd/ab8500-sysctrl.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
new file mode 100644
index 000000000..b6b44e2e3
--- /dev/null
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * AB8500 system control driver
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST Ericsson.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/export.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/reboot.h>
+#include <linux/signal.h>
+#include <linux/power_supply.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-sysctrl.h>
+
+/* RtcCtrl bits */
+#define AB8500_ALARM_MIN_LOW 0x08
+#define AB8500_ALARM_MIN_MID 0x09
+#define RTC_CTRL 0x0B
+#define RTC_ALARM_ENABLE 0x4
+
+static struct device *sysctrl_dev;
+
+static void ab8500_power_off(void)
+{
+ sigset_t old;
+ sigset_t all;
+ static const char * const pss[] = {"ab8500_ac", "ab8500_usb"};
+ int i;
+ bool charger_present = false;
+ union power_supply_propval val;
+ struct power_supply *psy;
+ int ret;
+
+ if (sysctrl_dev == NULL) {
+ pr_err("%s: sysctrl not initialized\n", __func__);
+ return;
+ }
+
+ /*
+ * If we have a charger connected and we're powering off,
+ * reboot into charge-only mode.
+ */
+
+ for (i = 0; i < ARRAY_SIZE(pss); i++) {
+ psy = power_supply_get_by_name(pss[i]);
+ if (!psy)
+ continue;
+
+ ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE,
+ &val);
+ power_supply_put(psy);
+
+ if (!ret && val.intval) {
+ charger_present = true;
+ break;
+ }
+ }
+
+ if (!charger_present)
+ goto shutdown;
+
+ /* Check if battery is known */
+ psy = power_supply_get_by_name("ab8500_btemp");
+ if (psy) {
+ ret = power_supply_get_property(psy,
+ POWER_SUPPLY_PROP_TECHNOLOGY, &val);
+ if (!ret && val.intval != POWER_SUPPLY_TECHNOLOGY_UNKNOWN) {
+ pr_info("Charger '%s' is connected with known battery",
+ pss[i]);
+ pr_info(" - Rebooting.\n");
+ machine_restart("charging");
+ }
+ power_supply_put(psy);
+ }
+
+shutdown:
+ sigfillset(&all);
+
+ if (!sigprocmask(SIG_BLOCK, &all, &old)) {
+ (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1,
+ AB8500_STW4500CTRL1_SWOFF |
+ AB8500_STW4500CTRL1_SWRESET4500N);
+ (void)sigprocmask(SIG_SETMASK, &old, NULL);
+ }
+}
+
+static inline bool valid_bank(u8 bank)
+{
+ return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
+ (bank == AB8500_SYS_CTRL2_BLOCK));
+}
+
+int ab8500_sysctrl_read(u16 reg, u8 *value)
+{
+ u8 bank;
+
+ if (sysctrl_dev == NULL)
+ return -EPROBE_DEFER;
+
+ bank = (reg >> 8);
+ if (!valid_bank(bank))
+ return -EINVAL;
+
+ return abx500_get_register_interruptible(sysctrl_dev, bank,
+ (u8)(reg & 0xFF), value);
+}
+EXPORT_SYMBOL(ab8500_sysctrl_read);
+
+int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value)
+{
+ u8 bank;
+
+ if (sysctrl_dev == NULL)
+ return -EPROBE_DEFER;
+
+ bank = (reg >> 8);
+ if (!valid_bank(bank)) {
+ pr_err("invalid bank\n");
+ return -EINVAL;
+ }
+
+ return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank,
+ (u8)(reg & 0xFF), mask, value);
+}
+EXPORT_SYMBOL(ab8500_sysctrl_write);
+
+static int ab8500_sysctrl_probe(struct platform_device *pdev)
+{
+ sysctrl_dev = &pdev->dev;
+
+ if (!pm_power_off)
+ pm_power_off = ab8500_power_off;
+
+ return 0;
+}
+
+static void ab8500_sysctrl_remove(struct platform_device *pdev)
+{
+ sysctrl_dev = NULL;
+
+ if (pm_power_off == ab8500_power_off)
+ pm_power_off = NULL;
+}
+
+static const struct of_device_id ab8500_sysctrl_match[] = {
+ { .compatible = "stericsson,ab8500-sysctrl", },
+ {}
+};
+
+static struct platform_driver ab8500_sysctrl_driver = {
+ .driver = {
+ .name = "ab8500-sysctrl",
+ .of_match_table = ab8500_sysctrl_match,
+ },
+ .probe = ab8500_sysctrl_probe,
+ .remove = ab8500_sysctrl_remove,
+};
+
+static int __init ab8500_sysctrl_init(void)
+{
+ return platform_driver_register(&ab8500_sysctrl_driver);
+}
+arch_initcall(ab8500_sysctrl_init);