Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- From 472a1b511d48e072f728048f354746fbe56a7541 Mon Sep 17 00:00:00 2001
- From: root <root@abyss.local>
- Date: Fri, 7 Oct 2022 01:24:50 +0300
- Subject: [PATCH] pwm: Add new pwm driver for ARM Macs
- Arm macs have a PWM controller that is hooked up to the keyboard backlight.
- This patch adds the controller driver and device tree bindings using pwm-leds.
- ---
- .../devicetree/bindings/pwm/pwm-apple.yaml | 41 +++++
- arch/arm64/boot/dts/apple/t600x-die0.dtsi | 9 ++
- .../arm64/boot/dts/apple/t600x-j314-j316.dtsi | 18 +++
- arch/arm64/boot/dts/apple/t8103-j293.dts | 16 ++
- arch/arm64/boot/dts/apple/t8103-j313.dts | 16 ++
- arch/arm64/boot/dts/apple/t8103.dtsi | 10 ++
- arch/arm64/boot/dts/apple/t8112-j413.dts | 16 ++
- arch/arm64/boot/dts/apple/t8112-j493.dts | 16 ++
- arch/arm64/boot/dts/apple/t8112.dtsi | 11 ++
- drivers/pwm/Kconfig | 12 ++
- drivers/pwm/Makefile | 1 +
- drivers/pwm/pwm-apple.c | 141 ++++++++++++++++++
- 12 files changed, 307 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/pwm/pwm-apple.yaml
- create mode 100644 drivers/pwm/pwm-apple.c
- diff --git a/Documentation/devicetree/bindings/pwm/pwm-apple.yaml b/Documentation/devicetree/bindings/pwm/pwm-apple.yaml
- new file mode 100644
- index 000000000000..fd751acec4eb
- --- /dev/null
- +++ b/Documentation/devicetree/bindings/pwm/pwm-apple.yaml
- @@ -0,0 +1,41 @@
- +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
- +%YAML 1.2
- +---
- +$id: http://devicetree.org/schemas/pwm/pwm-apple.yaml#
- +$schema: http://devicetree.org/meta-schemas/core.yaml#
- +
- +title: Apple FPWM controller
- +
- +maintainers: []
- +
- +description: |+
- + PWM controller used for keyboard backlight on ARM Macs
- +
- +properties:
- + compatible:
- + const: apple,s5l-fpwm
- + reg:
- + maxItems: 1
- +
- + clocks:
- + maxItems: 1
- +
- + "#pwm-cells":
- + const: 2
- +
- +required:
- + - compatible
- + - reg
- +
- +additionalProperties: false
- +
- +examples:
- + - |
- + fpwm1: fpwm@235044000 {
- + compatible = "apple,s5l-fpwm";
- + reg = <0x2 0x35044000 0x0 0x4000>;
- + power-domains = <&ps_fpwm1>;
- + clocks = <&clkref>;
- + #pwm-cells = <2>;
- + status = "disabled";
- + };
- diff --git a/arch/arm64/boot/dts/apple/t600x-die0.dtsi b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
- index 4c203778aa89..f90b6114036b 100644
- --- a/arch/arm64/boot/dts/apple/t600x-die0.dtsi
- +++ b/arch/arm64/boot/dts/apple/t600x-die0.dtsi
- @@ -274,6 +274,15 @@ spi3: spi@39b10c000 {
- status = "disabled";
- };
- + fpwm0: fpwm@39b030000 {
- + compatible = "apple,s5l-fpwm";
- + reg = <0x3 0xb9030000 0x0 0x4000>;
- + power-domains = <&ps_fpwm0>;
- + clocks = <&clkref>;
- + #pwm-cells = <2>;
- + status = "disabled";
- + };
- +
- serial0: serial@39b200000 {
- compatible = "apple,s5l-uart";
- reg = <0x3 0x9b200000 0x0 0x1000>;
- diff --git a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
- index bbe66ea64f09..9a79091a2e0d 100644
- --- a/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
- +++ b/arch/arm64/boot/dts/apple/t600x-j314-j316.dtsi
- @@ -9,6 +9,8 @@
- * Copyright The Asahi Linux Contributors
- */
- +#include <dt-bindings/leds/common.h>
- +
- / {
- aliases {
- serial0 = &serial0;
- @@ -339,4 +341,20 @@ codec {
- };
- };
- };
- + pwmleds {
- + compatible = "pwm-leds";
- + kbd-backlight {
- + pwms = <&fpwm0 0 40000>;
- + label = "kbd_backlight";
- + function = LED_FUNCTION_KBD_BACKLIGHT;
- + color = <LED_COLOR_ID_WHITE>;
- + max-brightness = <255>;
- + default-state = "keep";
- + pwm-names = "kbd-backlight";
- + };
- + };
- +};
- +
- +&fpwm0 {
- + status = "okay";
- };
- diff --git a/arch/arm64/boot/dts/apple/t8103-j293.dts b/arch/arm64/boot/dts/apple/t8103-j293.dts
- index 3a5ae54f0b9f..6237ce427939 100644
- --- a/arch/arm64/boot/dts/apple/t8103-j293.dts
- +++ b/arch/arm64/boot/dts/apple/t8103-j293.dts
- @@ -171,8 +171,24 @@ codec {
- };
- };
- };
- + pwmleds {
- + compatible = "pwm-leds";
- + kbd-backlight {
- + pwms = <&fpwm1 0 40000>;
- + label = "kbd_backlight";
- + function = LED_FUNCTION_KBD_BACKLIGHT;
- + color = <LED_COLOR_ID_WHITE>;
- + max-brightness = <255>;
- + default-state = "keep";
- + pwm-names = "kbd-backlight";
- + };
- + };
- };
- &framebuffer0 {
- backlight = <&backlight>;
- };
- +
- +&fpwm1 {
- + status = "okay";
- +};
- diff --git a/arch/arm64/boot/dts/apple/t8103-j313.dts b/arch/arm64/boot/dts/apple/t8103-j313.dts
- index b51f651d2326..94d55f0afd83 100644
- --- a/arch/arm64/boot/dts/apple/t8103-j313.dts
- +++ b/arch/arm64/boot/dts/apple/t8103-j313.dts
- @@ -148,8 +148,24 @@ codec {
- };
- };
- };
- + pwmleds {
- + compatible = "pwm-leds";
- + kbd-backlight {
- + pwms = <&fpwm1 0 40000>;
- + label = "kbd_backlight";
- + function = LED_FUNCTION_KBD_BACKLIGHT;
- + color = <LED_COLOR_ID_WHITE>;
- + max-brightness = <255>;
- + default-state = "keep";
- + pwm-names = "kbd-backlight";
- + };
- + };
- };
- &framebuffer0 {
- backlight = <&backlight>;
- };
- +
- +&fpwm1 {
- + status = "okay";
- +};
- diff --git a/arch/arm64/boot/dts/apple/t8103.dtsi b/arch/arm64/boot/dts/apple/t8103.dtsi
- index afb0688cb1c2..b9fee327361e 100644
- --- a/arch/arm64/boot/dts/apple/t8103.dtsi
- +++ b/arch/arm64/boot/dts/apple/t8103.dtsi
- @@ -12,6 +12,7 @@
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/pinctrl/apple.h>
- #include <dt-bindings/spmi/spmi.h>
- +#include <dt-bindings/leds/common.h>
- / {
- compatible = "apple,t8103", "apple,arm-platform";
- @@ -396,6 +397,15 @@ spi3: spi@23510c000 {
- status = "disabled"; /* only used in J293/J313 */
- };
- + fpwm1: fpwm@235044000 {
- + compatible = "apple,s5l-fpwm";
- + reg = <0x2 0x35044000 0x0 0x4000>;
- + power-domains = <&ps_fpwm1>;
- + clocks = <&clkref>;
- + #pwm-cells = <2>;
- + status = "disabled";
- + };
- +
- serial0: serial@235200000 {
- compatible = "apple,s5l-uart";
- reg = <0x2 0x35200000 0x0 0x1000>;
- diff --git a/arch/arm64/boot/dts/apple/t8112-j413.dts b/arch/arm64/boot/dts/apple/t8112-j413.dts
- index 0d4306a39fe8..7709c66ed850 100644
- --- a/arch/arm64/boot/dts/apple/t8112-j413.dts
- +++ b/arch/arm64/boot/dts/apple/t8112-j413.dts
- @@ -169,6 +169,18 @@ codec {
- };
- #endif
- };
- + pwmleds {
- + compatible = "pwm-leds";
- + kbd-backlight {
- + pwms = <&fpwm1 0 40000>;
- + label = "kbd_backlight";
- + function = LED_FUNCTION_KBD_BACKLIGHT;
- + color = <LED_COLOR_ID_WHITE>;
- + max-brightness = <255>;
- + default-state = "keep";
- + pwm-names = "kbd-backlight";
- + };
- + };
- };
- &framebuffer0 {
- @@ -180,3 +192,7 @@ multi-touch {
- firmware-name = "apple/tpmtfw-j413.bin";
- };
- };
- +
- +&fpwm1 {
- + status = "okay";
- +};
- diff --git a/arch/arm64/boot/dts/apple/t8112-j493.dts b/arch/arm64/boot/dts/apple/t8112-j493.dts
- index aa8c045cd1ac..92b75c3c325a 100644
- --- a/arch/arm64/boot/dts/apple/t8112-j493.dts
- +++ b/arch/arm64/boot/dts/apple/t8112-j493.dts
- @@ -158,6 +158,18 @@ codec {
- };
- #endif
- };
- + pwmleds {
- + compatible = "pwm-leds";
- + kbd-backlight {
- + pwms = <&fpwm1 0 40000>;
- + label = "kbd_backlight";
- + function = LED_FUNCTION_KBD_BACKLIGHT;
- + color = <LED_COLOR_ID_WHITE>;
- + max-brightness = <255>;
- + default-state = "keep";
- + pwm-names = "kbd-backlight";
- + };
- + };
- };
- &framebuffer0 {
- @@ -169,3 +181,7 @@ multi-touch {
- firmware-name = "apple/tpmtfw-j493.bin";
- };
- };
- +
- +&fpwm1 {
- + status = "okay";
- +};
- diff --git a/arch/arm64/boot/dts/apple/t8112.dtsi b/arch/arm64/boot/dts/apple/t8112.dtsi
- index 852937ec80ea..dda491f3d329 100644
- --- a/arch/arm64/boot/dts/apple/t8112.dtsi
- +++ b/arch/arm64/boot/dts/apple/t8112.dtsi
- @@ -12,6 +12,7 @@
- #include <dt-bindings/interrupt-controller/irq.h>
- #include <dt-bindings/pinctrl/apple.h>
- #include <dt-bindings/spmi/spmi.h>
- +#include <dt-bindings/leds/common.h>
- / {
- compatible = "apple,t8112", "apple,arm-platform";
- @@ -416,6 +417,16 @@ spi3: spi@23510c000 {
- status = "disabled";
- };
- + fpwm1: fpwm@235044000 {
- + compatible = "apple,s5l-fpwm";
- + reg = <0x2 0x35044000 0x0 0x4000>;
- + power-domains = <&ps_fpwm1>;
- + clocks = <&clkref>;
- + #pwm-cells = <2>;
- + status = "disabled";
- + };
- +
- +
- serial0: serial@235200000 {
- compatible = "apple,s5l-uart";
- reg = <0x2 0x35200000 0x0 0x1000>;
- diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
- index 904de8d61828..3ffb56549161 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
- + tristate "Apple SoC PWM support"
- + depends on ARCH_APPLE || COMPILE_TEST
- + help
- + Generic PWM framework driver for PWM controller present on
- + Apple SoCs
- +
- + Say Y here if you have an ARM Apple laptop, otherwise say N
- +
- + To compile this driver as a module, choose M here: the module
- + will be called pwm-apple.
- +
- config PWM_ATMEL
- tristate "Atmel PWM support"
- depends on ARCH_AT91 || COMPILE_TEST
- diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
- index 5c08bdb817b4..bf0c04ce704e 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) += pwm-apple.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.c b/drivers/pwm/pwm-apple.c
- new file mode 100644
- index 000000000000..3e8f2ddb05c0
- --- /dev/null
- +++ b/drivers/pwm/pwm-apple.c
- @@ -0,0 +1,141 @@
- +// SPDX-License-Identifier: GPL-2.0
- +/*
- + * Driver for the Apple SoC PWM controller
- + *
- + * Copyright The Asahi Linux Contributors
- + */
- +
- +#include <linux/module.h>
- +#include <linux/of.h>
- +#include <linux/of_device.h>
- +#include <linux/platform_device.h>
- +#include <linux/pwm.h>
- +#include <linux/io.h>
- +#include <linux/clk.h>
- +#include <linux/pm_runtime.h>
- +
- +#define PWM_CONTROL 0x00
- +#define PWM_APPLY_MAGIC 0x4239
- +#define PWM_ON_CYCLES 0x1c
- +#define PWM_OFF_CYCLES 0x18
- +
- +#define CTRL_ENABLE BIT(0)
- +#define CTRL_MODE BIT(2)
- +#define CTRL_UPDATE BIT(5)
- +#define CTRL_TRIGGER BIT(9)
- +#define CTRL_INVERT BIT(10)
- +#define CTRL_OUTPUT_ENABLE BIT(14)
- +
- +struct apple_pwm {
- + struct pwm_chip chip;
- + void __iomem *base;
- + struct clk *clk;
- + u64 clkrate;
- +};
- +
- +static int apple_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
- + const struct pwm_state *state)
- +{
- + struct apple_pwm *fpwm;
- + u64 on_cycles, off_cycles;
- +
- + fpwm = container_of(chip, struct apple_pwm, chip);
- + on_cycles = fpwm->clkrate * state->duty_cycle / NSEC_PER_SEC;
- + off_cycles = (fpwm->clkrate * state->period / NSEC_PER_SEC) - on_cycles;
- + if (state->enabled) {
- + writel(on_cycles, fpwm->base + PWM_ON_CYCLES);
- + writel(off_cycles, fpwm->base + PWM_OFF_CYCLES);
- + writel(CTRL_ENABLE | CTRL_OUTPUT_ENABLE | CTRL_UPDATE,
- + fpwm->base + PWM_CONTROL);
- + } else {
- + writel(0, fpwm->base + PWM_CONTROL);
- + }
- + return 0;
- +}
- +
- +static void apple_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
- + struct pwm_state *state)
- +{
- + struct apple_pwm *fpwm;
- + u32 on_cycles, off_cycles, ctrl;
- +
- + fpwm = container_of(chip, struct apple_pwm, chip);
- +
- + ctrl = readl(fpwm->base + PWM_CONTROL);
- + on_cycles = readl(fpwm->base + PWM_ON_CYCLES);
- + off_cycles = readl(fpwm->base + PWM_OFF_CYCLES);
- +
- + state->enabled = (ctrl & CTRL_ENABLE) && (ctrl & CTRL_OUTPUT_ENABLE);
- + state->polarity = PWM_POLARITY_NORMAL;
- + state->duty_cycle = on_cycles / fpwm->clkrate * NSEC_PER_SEC;
- + state->period = (off_cycles / fpwm->clkrate * NSEC_PER_SEC)
- + + state->duty_cycle;
- +}
- +
- +static const struct pwm_ops apple_pwm_ops = {
- + .apply = apple_pwm_apply,
- + .get_state = apple_pwm_get_state,
- + .owner = THIS_MODULE,
- +};
- +
- +static void apple_pwm_clk_disable_unprepare(void *data)
- +{
- + clk_disable_unprepare(data);
- +}
- +
- +static int apple_pwm_probe(struct platform_device *pdev)
- +{
- + struct apple_pwm *pwm;
- + int ret;
- +
- + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
- + if (!pwm)
- + return -ENOMEM;
- +
- + pwm->base = devm_platform_ioremap_resource(pdev, 0);
- + if (IS_ERR(pwm->base))
- + return PTR_ERR(pwm->base);
- +
- + platform_set_drvdata(pdev, pwm);
- +
- + pwm->clk = devm_clk_get(&pdev->dev, NULL);
- + if (IS_ERR(pwm->clk))
- + return PTR_ERR(pwm->clk);
- +
- + ret = clk_prepare_enable(pwm->clk);
- + if (ret)
- + return ret;
- +
- + pwm->clkrate = clk_get_rate(pwm->clk);
- +
- + ret = devm_add_action_or_reset(&pdev->dev,
- + apple_pwm_clk_disable_unprepare, pwm->clk);
- + if (ret)
- + return ret;
- +
- + pwm->chip.dev = &pdev->dev;
- + pwm->chip.npwm = 1;
- + pwm->chip.ops = &apple_pwm_ops;
- +
- + ret = devm_pwmchip_add(&pdev->dev, &pwm->chip);
- + return ret;
- +}
- +
- +static const struct of_device_id apple_pwm_of_match[] = {
- + { .compatible = "apple,s5l-fpwm" },
- + {}
- +};
- +MODULE_DEVICE_TABLE(of, apple_pwm_of_match);
- +
- +static struct platform_driver apple_pwm_driver = {
- + .probe = apple_pwm_probe,
- + .driver = {
- + .name = "apple-pwm",
- + .owner = THIS_MODULE,
- + .of_match_table = apple_pwm_of_match,
- + },
- +};
- +module_platform_driver(apple_pwm_driver);
- +
- +MODULE_DESCRIPTION("Apple SoC PWM driver");
- +MODULE_LICENSE("GPL");
- --
- 2.37.3
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement