From 639eea96d638cc3984dd1b8360d7d547dd82a2e9 Mon Sep 17 00:00:00 2001 From: Dj Date: Sat, 10 Oct 2026 23:47:32 -0400 Subject: [PATCH] mfd: macsmc: Add T6050 profile and described pcIO outputs Expose notifications and described hwmon inputs on T6050. Register the pcIO GPIO provider only where DT supplies unique command templates, and validate the writable key and complete eight-byte writes. Preserve existing GPIO implementations and newer notification cleanup. Do not instantiate unqualified T6050 power, reboot or RTC functions. Signed-off-by: Dj --- .../bindings/gpio/apple,smc-pcio-gpio.yaml | 40 +++++++++++ .../devicetree/bindings/mfd/apple,smc.yaml | 7 +- arch/arm64/configs/aurora-apif.config | 7 ++ drivers/gpio/gpio-macsmc.c | 72 ++++++++++++++++++- drivers/mfd/macsmc.c | 32 +++++++-- 5 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 Documentation/devicetree/bindings/gpio/apple,smc-pcio-gpio.yaml diff --git a/Documentation/devicetree/bindings/gpio/apple,smc-pcio-gpio.yaml b/Documentation/devicetree/bindings/gpio/apple,smc-pcio-gpio.yaml new file mode 100644 index 0000000000000..94d9672189fc6 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/apple,smc-pcio-gpio.yaml @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: GPL-2.0-only +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/gpio/apple,smc-pcio-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple SMC pcIO output GPIOs + +maintainers: + - Dj + +description: | + The writable eight-byte pcIO SMC key controls outputs through board + command templates. Each template has its low 16 bits clear; the driver + inserts a boolean output level and sends the little-endian command. + Input reads and mode changes are not supported by this interface. + +properties: + compatible: + const: apple,smc-pcio-gpio + + gpio-controller: true + + '#gpio-cells': + const: 2 + + apple,output-commands: + $ref: /schemas/types.yaml#/definitions/uint64-array + minItems: 1 + maxItems: 64 + uniqueItems: true + description: Unique command templates with low 16 bits clear, in GPIO order + +required: + - compatible + - gpio-controller + - '#gpio-cells' + - apple,output-commands + +additionalProperties: false diff --git a/Documentation/devicetree/bindings/mfd/apple,smc.yaml b/Documentation/devicetree/bindings/mfd/apple,smc.yaml index 31d1940f9d3dc..82831462fba8d 100644 --- a/Documentation/devicetree/bindings/mfd/apple,smc.yaml +++ b/Documentation/devicetree/bindings/mfd/apple,smc.yaml @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) AND GPL-2.0-only %YAML 1.2 --- $id: http://devicetree.org/schemas/mfd/apple,smc.yaml# @@ -16,6 +16,7 @@ description: properties: compatible: oneOf: + - const: apple,t6050-smc - items: - enum: - apple,t6020-smc @@ -45,7 +46,9 @@ properties: maxItems: 1 gpio: - $ref: /schemas/gpio/apple,smc-gpio.yaml + oneOf: + - $ref: /schemas/gpio/apple,smc-gpio.yaml + - $ref: /schemas/gpio/apple,smc-pcio-gpio.yaml reboot: $ref: /schemas/power/reset/apple,smc-reboot.yaml diff --git a/arch/arm64/configs/aurora-apif.config b/arch/arm64/configs/aurora-apif.config index 7389821ef0447..128b10ddb9ddd 100644 --- a/arch/arm64/configs/aurora-apif.config +++ b/arch/arm64/configs/aurora-apif.config @@ -18,3 +18,10 @@ CONFIG_NVMEM=y CONFIG_NVMEM_APPLE_SPMI=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_APPLE_SPMI_PMU=y +CONFIG_MFD_MACSMC=y +CONFIG_GPIO_MACSMC=y +CONFIG_INPUT=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_MACSMC_INPUT=y +CONFIG_HWMON=y +CONFIG_SENSORS_MACSMC_HWMON=y diff --git a/drivers/gpio/gpio-macsmc.c b/drivers/gpio/gpio-macsmc.c index 471bce2e54b4f..257c731528b29 100644 --- a/drivers/gpio/gpio-macsmc.c +++ b/drivers/gpio/gpio-macsmc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) AND GPL-2.0-only /* * Apple SMC GPIO driver * Copyright The Asahi Linux Contributors @@ -14,6 +14,7 @@ #include #include #include +#include #define MAX_GPIO 64 @@ -91,6 +92,7 @@ struct macsmc_gpio { struct apple_smc *smc; struct gpio_chip gc; + u64 *output_commands; int first_index; smc_key base_key; @@ -296,6 +298,71 @@ static int macsmc_gpio_init_valid_mask(struct gpio_chip *gc, return 0; } +/* Each DT template identifies one output; its low 16 bits carry the value. */ +static int macsmc_pcio_set(struct gpio_chip *gc, unsigned int offset, int value) +{ + struct macsmc_gpio *smcgp = gpiochip_get_data(gc); + u8 command[8]; + int ret; + + put_unaligned_le64(smcgp->output_commands[offset] | !!value, command); + ret = apple_smc_write(smcgp->smc, SMC_KEY(pcIO), command, sizeof(command)); + return ret < 0 ? ret : ret == sizeof(command) ? 0 : -EIO; +} + +static int macsmc_pcio_get(struct gpio_chip *gc, unsigned int offset) +{ + /* The native output command has no established input/readback operation. */ + return -EOPNOTSUPP; +} + +static int macsmc_pcio_get_direction(struct gpio_chip *gc, unsigned int offset) +{ + return GPIO_LINE_DIRECTION_OUT; +} + +static int macsmc_pcio_probe(struct macsmc_gpio *smcgp) +{ + struct device *dev = smcgp->dev; + struct apple_smc_key_info info; + int count, ret; + + ret = apple_smc_get_key_info(smcgp->smc, SMC_KEY(pcIO), &info); + if (ret < 0) + return ret; + if (info.size != 8 || !(info.flags & APPLE_SMC_WRITABLE)) + return dev_err_probe(dev, -EINVAL, "pcIO is not an eight-byte output key\n"); + count = of_property_count_u64_elems(dev->of_node, "apple,output-commands"); + if (count <= 0 || count > MAX_GPIO) + return -EINVAL; + smcgp->output_commands = devm_kcalloc(dev, count, sizeof(u64), GFP_KERNEL); + if (!smcgp->output_commands) + return -ENOMEM; + ret = of_property_read_u64_array(dev->of_node, "apple,output-commands", + smcgp->output_commands, count); + if (ret) + return ret; + for (int i = 0; i < count; i++) { + if (smcgp->output_commands[i] & 0xffff) + return -EINVAL; + for (int j = 0; j < i; j++) + if (smcgp->output_commands[i] == smcgp->output_commands[j]) + return -EINVAL; + } + + smcgp->gc.label = "macsmc-pcio-output"; + smcgp->gc.owner = THIS_MODULE; + smcgp->gc.get = macsmc_pcio_get; + smcgp->gc.set = macsmc_pcio_set; + smcgp->gc.direction_output = macsmc_pcio_set; + smcgp->gc.get_direction = macsmc_pcio_get_direction; + smcgp->gc.can_sleep = true; + smcgp->gc.ngpio = count; + smcgp->gc.base = -1; + smcgp->gc.parent = dev; + return devm_gpiochip_add_data(dev, &smcgp->gc, smcgp); +} + struct macsmc_gpio_of_match_data { smc_key base_key; }; @@ -314,6 +381,8 @@ static int macsmc_gpio_probe(struct platform_device *pdev) smcgp->dev = &pdev->dev; smcgp->smc = smc; + if (device_is_compatible(&pdev->dev, "apple,smc-pcio-gpio")) + return macsmc_pcio_probe(smcgp); smcgp->base_key = data ? data->base_key : _SMC_KEY("gP\0\0"); smcgp->j700_pcio = of_machine_is_compatible("apple,j700") && device_is_compatible(&pdev->dev, "apple,smc-gpio"); @@ -357,6 +426,7 @@ static const struct macsmc_gpio_of_match_data macsmc_gpio_low_data = { }; static const struct of_device_id macsmc_gpio_of_table[] = { + { .compatible = "apple,smc-pcio-gpio" }, { .compatible = "apple,smc-gpio", .data = &macsmc_gpio_up_data, diff --git a/drivers/mfd/macsmc.c b/drivers/mfd/macsmc.c index 8cdc59a7dd88c..eb187dd588300 100644 --- a/drivers/mfd/macsmc.c +++ b/drivers/mfd/macsmc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only OR MIT +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) AND GPL-2.0-only /* * Apple SMC (System Management Controller) MFD driver * @@ -53,6 +53,15 @@ static const struct mfd_cell apple_smc_devs[] = { MFD_CELL_OF("macsmc-rtc", NULL, NULL, 0, 0, "apple,smc-rtc"), }; +/* This profile exposes notifications and the explicitly described outputs. */ +static const struct mfd_cell apple_smc_t6050_devs[] = { + MFD_CELL_NAME("macsmc-input"), + MFD_CELL_OF("macsmc-hwmon", NULL, NULL, 0, 0, "apple,smc-hwmon"), +}; + +static const struct mfd_cell apple_smc_pcio_dev = + MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-pcio-gpio"); + /* The second GPIO bank ('gp' keys) only exists on some SMCs. */ static const struct mfd_cell apple_smc_low_gpio_dev = MFD_CELL_OF("macsmc-low-gpio", NULL, NULL, 0, 0, "apple,smc-low-gpio"); @@ -479,12 +488,26 @@ static int apple_smc_probe(struct platform_device *pdev) if (ret) return ret; - ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, - apple_smc_devs, ARRAY_SIZE(apple_smc_devs), - NULL, 0, NULL); + if (of_device_is_compatible(dev->of_node, "apple,t6050-smc")) + ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, + apple_smc_t6050_devs, + ARRAY_SIZE(apple_smc_t6050_devs), NULL, 0, NULL); + else + 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"); + np = of_get_compatible_child(dev->of_node, "apple,smc-pcio-gpio"); + if (np) { + of_node_put(np); + ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, + &apple_smc_pcio_dev, 1, NULL, 0, NULL); + if (ret) + return dev_err_probe(dev, ret, "Failed to register pcIO outputs\n"); + } + /* * Register the second GPIO bank only where the device tree describes * it: the MFD core would otherwise create an unbound device and warn @@ -504,6 +527,7 @@ static int apple_smc_probe(struct platform_device *pdev) } static const struct of_device_id apple_smc_of_match[] = { + { .compatible = "apple,t6050-smc" }, { .compatible = "apple,t8103-smc" }, { .compatible = "apple,smc" }, {},