From 030ffd4ab6f35fbf23b272e1e37714dbf6b276f9 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Mon, 9 Aug 2021 08:06:39 +0000 Subject: [PATCH 1/3] dt-bindings: pwm: bindings for Apple M1 FPWM This is a PWM found on the Apple M1 SoC. On at least some MacBook Pros, it's connected to the keyboard backlight. Signed-off-by: Pip Cet --- .../devicetree/bindings/pwm/apple,fpwm.yaml | 45 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 46 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/apple,fpwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/apple,fpwm.yaml b/Documentation/devicetree/bindings/pwm/apple,fpwm.yaml new file mode 100644 index 00000000000000..a01ae4d5c13418 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/apple,fpwm.yaml @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/apple,fpwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Apple M1 FPWM controller + +maintainers: + - Pip Cet + +description: + Single-channel PWM connected to the keyboard backlight on at least + some MacBook Pros. + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + const: apple,t8103-fpwm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#pwm-cells": + const: 0 + +additionalProperties: false + +required: + - reg + - clocks + +examples: + - | + pwm@235044000 { + compatible = "apple,t8103-fpwm"; + reg = <0x35044000 0x4000>; + clocks = <&fpwm0_clk>; + #pwm-cells = <0>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 5f3ef429859456..70f5df0e47a540 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1702,6 +1702,7 @@ T: git https://github.com/AsahiLinux/linux.git F: Documentation/devicetree/bindings/arm/apple.yaml F: Documentation/devicetree/bindings/interrupt-controller/apple,aic.yaml F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml +F: Documentation/devicetree/bindings/pwm/apple,fpwm.yaml F: arch/arm64/boot/dts/apple/ F: drivers/irqchip/irq-apple-aic.c F: include/dt-bindings/interrupt-controller/apple-aic.h From d1a12e012701154eccd38ea4383ccd00949d0509 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Mon, 9 Aug 2021 08:07:19 +0000 Subject: [PATCH 2/3] pwm: apple-m1: Add Apple M1 FPWM controller driver This PWM module on the Apple M1 SoC is connected to the keyboard backlight on at least some MacBook Pros (J293). Signed-off-by: Pip Cet --- MAINTAINERS | 1 + drivers/pwm/Kconfig | 12 +++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-apple-m1.c | 165 +++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+) create mode 100644 drivers/pwm/pwm-apple-m1.c diff --git a/MAINTAINERS b/MAINTAINERS index 70f5df0e47a540..c51958f2be748d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1705,6 +1705,7 @@ F: Documentation/devicetree/bindings/pinctrl/apple,pinctrl.yaml F: Documentation/devicetree/bindings/pwm/apple,fpwm.yaml F: arch/arm64/boot/dts/apple/ F: drivers/irqchip/irq-apple-aic.c +F: drivers/pwm/pwm-apple-m1.c F: include/dt-bindings/interrupt-controller/apple-aic.h F: include/dt-bindings/pinctrl/apple.h diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index c76adedd58c9f0..5fdebb19a84cba 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -51,6 +51,18 @@ config PWM_AB8500 To compile this driver as a module, choose M here: the module will be called pwm-ab8500. +config PWM_APPLE_M1 + tristate "Apple M1 PWM support" + depends on ARCH_APPLE || COMPILE_TEST + depends on HAS_IOMEM && OF + help + PWM driver for the FPWM found on Apple M1 SoCs. This is + connected to the keyboard backlight on at least some + MacBook Pros. + + To compile this driver as a module, choose M here: the module + will be called pwm-apple-m1. + config PWM_ATMEL tristate "Atmel PWM support" depends on ARCH_AT91 || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 708840b7fba8d8..ce8af436e538e8 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_PWM) += core.o obj-$(CONFIG_PWM_SYSFS) += sysfs.o obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o +obj-$(CONFIG_PWM_APPLE_M1) += pwm-apple-m1.o obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o diff --git a/drivers/pwm/pwm-apple-m1.c b/drivers/pwm/pwm-apple-m1.c new file mode 100644 index 00000000000000..9325b4092233ef --- /dev/null +++ b/drivers/pwm/pwm-apple-m1.c @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Driver for Apple M1 FPWM + * + * Used for the keyboard backlight on at least some MacBook Pros. + * + * This driver requires a clock, which should provide the standard 24 MHz + * reference clock rate on M1 systems. + * + * The actual hardware appears to provide interrupt facilities and + * other unknown features, but those have not been reverse-engineered + * yet. + * + * Hardware documentation: + * + * https://github.com/AsahiLinux/docs/wiki/HW:MacBook-Pro-keyboard-backlight-(FPWM0) + * + * Copyright (C) 2021 Pip Cet + * + * Based on pwm-twl-led.c, which is: + * + * Copyright (C) 2012 Texas Instruments + * Author: Peter Ujfalusi + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define FPWM_CONTROL 0x00 +#define CONTROL_UPDATE 0x4239 +#define CONTROL_DISABLE 0 +#define FPWM_STATUS 0x08 +#define FPWM_COUNT_OFF 0x18 +#define FPWM_COUNT_ON 0x1c + +struct fpwm_chip { + struct pwm_chip chip; + void __iomem *reg; + struct clk *clk; + u64 rate; +}; + +static inline struct fpwm_chip *to_fpwm(struct pwm_chip *chip) +{ + return container_of(chip, struct fpwm_chip, chip); +} + +static int fpwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct fpwm_chip *fpwm = to_fpwm(chip); + long duty_ticks = div_u64(duty_ns * fpwm->rate, 1000000000); + long period_ticks = div_u64(period_ns * fpwm->rate, 1000000000); + long off_ticks = period_ticks - duty_ticks; + + writel(duty_ticks, fpwm->reg + FPWM_COUNT_ON); + writel(off_ticks, fpwm->reg + FPWM_COUNT_OFF); + writel(CONTROL_UPDATE, fpwm->reg + FPWM_CONTROL); + + return 0; +} + +static int fpwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fpwm_chip *fpwm = to_fpwm(chip); + + writel(CONTROL_UPDATE, fpwm->reg + FPWM_CONTROL); + + return 0; +} + +static void fpwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct fpwm_chip *fpwm = to_fpwm(chip); + + writel(CONTROL_DISABLE, fpwm->reg + FPWM_CONTROL); +} + +static const struct pwm_ops fpwm_ops = { + .enable = fpwm_enable, + .disable = fpwm_disable, + .config = fpwm_config, + .owner = THIS_MODULE, +}; + +static int fpwm_probe(struct platform_device *pdev) +{ + struct fpwm_chip *fpwm; + struct resource *res; + int ret; + + fpwm = devm_kzalloc(&pdev->dev, sizeof(*fpwm), GFP_KERNEL); + if (!fpwm) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + fpwm->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(fpwm->clk)) + return PTR_ERR(fpwm->clk); + + ret = clk_prepare_enable(fpwm->clk); + if (ret) + return ret; + + fpwm->rate = clk_get_rate(fpwm->clk); + + fpwm->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fpwm->reg)) { + clk_disable_unprepare(fpwm->clk); + return PTR_ERR(fpwm->reg); + } + + fpwm->chip.ops = &fpwm_ops; + fpwm->chip.npwm = 1; + fpwm->chip.dev = &pdev->dev; + fpwm->chip.base = -1; + + ret = devm_pwmchip_add(&pdev->dev, &fpwm->chip); + if (ret < 0) { + clk_disable_unprepare(fpwm->clk); + return ret; + } + + platform_set_drvdata(pdev, fpwm); + + return 0; +} + +static int fpwm_remove(struct platform_device *pdev) +{ + struct fpwm_chip *fpwm = platform_get_drvdata(pdev); + + clk_disable_unprepare(fpwm->clk); + + return 0; +} + +static const struct of_device_id fpwm_of_match[] = { + { .compatible = "apple,t8103-fpwm" }, + { }, +}; +MODULE_DEVICE_TABLE(of, fpwm_of_match); + +static struct platform_driver fpwm_driver = { + .driver = { + .name = "apple-m1-fpwm", + .of_match_table = of_match_ptr(fpwm_of_match), + }, + .probe = fpwm_probe, + .remove = fpwm_remove, +}; +module_platform_driver(fpwm_driver); + +MODULE_AUTHOR("Pip Cet "); +MODULE_DESCRIPTION("PWM driver for Apple M1 FPWM"); +MODULE_LICENSE("GPL"); From 08b13063a51f08cb9330d9a165ef58de8c4f04b8 Mon Sep 17 00:00:00 2001 From: Pip Cet Date: Mon, 9 Aug 2021 07:59:41 +0000 Subject: [PATCH 3/3] arm64: apple: Add initial Apple MacBook Pro (13-inch, M1) devicetree Model number is J293, this is based on the 2020/2021 model. Signed-off-by: Pip Cet --- arch/arm64/boot/dts/apple/Makefile | 2 +- arch/arm64/boot/dts/apple/t8103-j293.dts | 54 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/apple/t8103-j293.dts diff --git a/arch/arm64/boot/dts/apple/Makefile b/arch/arm64/boot/dts/apple/Makefile index cbbd701ebf05bf..9f09980d6e6837 100644 --- a/arch/arm64/boot/dts/apple/Makefile +++ b/arch/arm64/boot/dts/apple/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_ARCH_APPLE) += t8103-j274.dtb +dtb-$(CONFIG_ARCH_APPLE) += t8103-j274.dtb t8103-j293.dtb diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts new file mode 100644 index 00000000000000..dbaff1295c17d4 --- /dev/null +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0+ OR MIT +/* + * Apple MacBook Pro (13-inch, M1, 2020) + * + * target-type: J293 + * + * Copyright The Asahi Linux Contributors + */ + +/dts-v1/; + +#include "t8103.dtsi" + +/ { + compatible = "apple,j293", "apple,t8103", "apple,arm-platform"; + model = "Apple MacBook Pro (13-inch, M1, 2020)"; + + aliases { + serial0 = &serial0; + }; + + soc { + pwm@235044000 { + compatible = "apple,t8103-fpwm"; + reg = <0x2 0x35044000 0x0 0x4000>; + clocks = <&clk24>; + #pwm-cells = <0>; + }; + }; + + chosen { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + stdout-path = "serial0"; + + framebuffer0: framebuffer@0 { + compatible = "apple,simple-framebuffer", "simple-framebuffer"; + reg = <0 0 0 0>; /* To be filled by loader */ + /* Format properties will be added by loader */ + status = "disabled"; + }; + }; + + memory@800000000 { + device_type = "memory"; + reg = <0x8 0 0x2 0>; /* To be filled by loader */ + }; +}; + +&serial0 { + status = "okay"; +};