Hi Sasha Finkelstein, Thanks for the patch. > Subject: [PATCH v2 2/4] pwm: Add Apple PWM controller > > Adds the Apple PWM controller driver. > > Signed-off-by: Sasha Finkelstein <fnkl.kernel@xxxxxxxxx> > --- > drivers/pwm/Kconfig | 12 ++++ > drivers/pwm/Makefile | 1 + > drivers/pwm/pwm-apple.c | 127 > ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 140 insertions(+) > create mode 100644 drivers/pwm/pwm-apple.c > > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index > 60d13a949bc5..c3be11468414 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 > 7bf1a29f02b8..19899b912e00 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..7b2936346f4e > --- /dev/null > +++ b/drivers/pwm/pwm-apple.c > @@ -0,0 +1,127 @@ > +// SPDX-License-Identifier: GPL-2.0 OR MIT > +/* > + * 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> > +#include <linux/math64.h> May be sort header alphabetically?? > + > +#define PWM_CONTROL 0x00 > +#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; > + 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); > + if (state->enabled) { > + on_cycles = mul_u64_u64_div_u64(fpwm->clkrate, > + state->duty_cycle, NSEC_PER_SEC); > + off_cycles = mul_u64_u64_div_u64(fpwm->clkrate, > + state->period, NSEC_PER_SEC) - > on_cycles; > + 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 = div_u64(on_cycles, fpwm->clkrate) * > NSEC_PER_SEC; > + state->period = div_u64(off_cycles + on_cycles, fpwm->clkrate) * > +NSEC_PER_SEC; } > + > +static const struct pwm_ops apple_pwm_ops = { > + .apply = apple_pwm_apply, > + .get_state = apple_pwm_get_state, > + .owner = THIS_MODULE, > +}; > + > +static int apple_pwm_probe(struct platform_device *pdev) { > + struct apple_pwm *pwm; > + struct clk *clk; > + 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); > + > + clk = devm_clk_get_enabled(&pdev->dev, NULL); > + if (IS_ERR(clk)) > + return PTR_ERR(clk); What is your use case? PWM is configured by bootloader intially?? Or PWM is configured by Linux not by the bootloader? Or Driver needs to support both ?? Cheers, Biju > + > + pwm->clkrate = clk_get_rate(clk); > + 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("Dual > +MIT/GPL"); > -- > 2.37.3 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@xxxxxxxxxxxxxxxxxxx > https://jpn01.safelinks.protection.outlook.com/?url=http%3A%2F%2Flists > .infradead.org%2Fmailman%2Flistinfo%2Flinux-arm- > kernel&data=05%7C01%7Cbiju.das.jz%40bp.renesas.com%7C0ff5a9275b954 > eff39ae08dabcde3c28%7C53d82571da1947e49cb4625a166a4a2a%7C0%7C0%7C63802 > 9959918512569%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2lu > MzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=zdoRENBcN > FUDLdqC8wOspyvoOzRsTkBkS01Q8ff9okk%3D&reserved=0