forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 114
Apple M1 FPWM (MacBook Pro keyboard backlight) driver #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <pipcet@gmail.com> | ||
|
|
||
| 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>; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 <pipcet@gmail.com> | ||
| * | ||
| * Based on pwm-twl-led.c, which is: | ||
| * | ||
| * Copyright (C) 2012 Texas Instruments | ||
| * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> | ||
| */ | ||
|
|
||
| #include <linux/clk.h> | ||
| #include <linux/io.h> | ||
| #include <linux/math64.h> | ||
| #include <linux/module.h> | ||
| #include <linux/of.h> | ||
| #include <linux/platform_device.h> | ||
| #include <linux/pwm.h> | ||
| #include <linux/slab.h> | ||
|
|
||
| #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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Retracted |
||
|
|
||
| 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 <pipcet@gmail.com>"); | ||
| MODULE_DESCRIPTION("PWM driver for Apple M1 FPWM"); | ||
| MODULE_LICENSE("GPL"); | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I'm concerned, that's just a magic constant, derived at experimentally. Should there be a comment explaining that?