Message ID | 20230922092848.72664-3-william.qiu@starfivetech.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:172:b0:3f2:4152:657d with SMTP id h50csp5433678vqi; Fri, 22 Sep 2023 02:32:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFZQdiFGNfxPlbsXkeX3WQf4Kjh4qjeTocwGcRV6GI/KYSFXMC0gAa7VwBFKakPzckhwWww X-Received: by 2002:a05:6a00:3a1e:b0:68a:3ba3:e249 with SMTP id fj30-20020a056a003a1e00b0068a3ba3e249mr8855619pfb.16.1695375163574; Fri, 22 Sep 2023 02:32:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695375163; cv=none; d=google.com; s=arc-20160816; b=J1X1uEf3Iqk9Xrob4hz93lbOY5xwSVAm7K3BzmAupQB+kffvv59jaRoPYRUudDDE0C 2BEpk4imtQq3/XjX+mSVGc5+tCSZXvwPTaJnf3/tnOUTFlVDZHQ/W8599G2kqZ2SX0NP lxoPRwdM/XQoraAlh89xmW+cibcMC6ki03TJh8zwUpsZ4JW+3kxKPvuxgpNw+McCV+Jd WS5M6TZnmxcX2IKAHJNxiVF5dvyMrTphnHlkX7s4oVommAwMMg8TqHh9PU4bO1bYzpwj fHizvi9fHwRuhJmVV9/xBRt6YbhsHJqtpymNNAz5PDBPV0LFY5jGNur/iJj6r2IjVIwx UXSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=7lyD79G2iftiGZOxiPqraxaGqTVQ44pvHl60+AxjeHk=; fh=T4gzk7+hgrXGjSNvKGZTlbuKXCiuDaGkxvCBgfgONjs=; b=iCrSRluWfnMKjKqqq69cBB7O5NOJJRKi9uXEpUeR0gaE8zkAC5H7lXMZYGqP7Gk644 AzwOqWmQBgXMJRevmPR+5873g2TI04zg+WHlPCn6RaUHghRVkjOI7laDUVgeQ/1r/vDP PH+tsnp5MCFD/hoIB0Uk/NW6elt+izg7Lw4tmUW2vZgQRY39nGVhVup8MUNfF+R/w4rw Ul2QNAiI4G6EkFayzV1FPWgzVbBDP4TXTQN7T8MbecVg1d0j+WUl6P0AwP2WgT5WjYuT DDjxXHNSumunkNPqGT+sJhwJRGIRA/Ko4ggqrW+5aDHyqmrvPo+Velkhx/01hpBZjj8J n9sw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:1 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from morse.vger.email (morse.vger.email. [2620:137:e000::3:1]) by mx.google.com with ESMTPS id v15-20020a65460f000000b005704979833csi3227247pgq.855.2023.09.22.02.32.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Sep 2023 02:32:43 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:1 as permitted sender) client-ip=2620:137:e000::3:1; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:1 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by morse.vger.email (Postfix) with ESMTP id E033C83FC3BE; Fri, 22 Sep 2023 02:29:26 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at morse.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232977AbjIVJ3M convert rfc822-to-8bit (ORCPT <rfc822;chrisfriedt@gmail.com> + 30 others); Fri, 22 Sep 2023 05:29:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46954 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233001AbjIVJ3H (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 22 Sep 2023 05:29:07 -0400 Received: from ex01.ufhost.com (ex01.ufhost.com [61.152.239.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A9BF31BC; Fri, 22 Sep 2023 02:28:59 -0700 (PDT) Received: from EXMBX165.cuchost.com (unknown [175.102.18.54]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "EXMBX165", Issuer "EXMBX165" (not verified)) by ex01.ufhost.com (Postfix) with ESMTP id E518624E2A1; Fri, 22 Sep 2023 17:28:51 +0800 (CST) Received: from EXMBX168.cuchost.com (172.16.6.78) by EXMBX165.cuchost.com (172.16.6.75) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 22 Sep 2023 17:28:52 +0800 Received: from williamqiu-virtual-machine.starfivetech.com (171.223.208.138) by EXMBX168.cuchost.com (172.16.6.78) with Microsoft SMTP Server (TLS) id 15.0.1497.42; Fri, 22 Sep 2023 17:28:50 +0800 From: William Qiu <william.qiu@starfivetech.com> To: <devicetree@vger.kernel.org>, <linux-kernel@vger.kernel.org>, <linux-riscv@lists.infradead.org>, <linux-pwm@vger.kernel.org> CC: Emil Renner Berthing <kernel@esmil.dk>, Rob Herring <robh+dt@kernel.org>, Thierry Reding <thierry.reding@gmail.com>, Philipp Zabel <p.zabel@pengutronix.de>, Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>, Conor Dooley <conor+dt@kernel.org>, =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= <u.kleine-koenig@pengutronix.de>, "Hal Feng" <hal.feng@starfivetech.com>, Paul Walmsley <paul.walmsley@sifive.com>, Palmer Dabbelt <palmer@dabbelt.com>, Albert Ou <aou@eecs.berkeley.edu>, William Qiu <william.qiu@starfivetech.com> Subject: [PATCH v5 2/4] pwm: starfive: Add PWM driver support Date: Fri, 22 Sep 2023 17:28:46 +0800 Message-ID: <20230922092848.72664-3-william.qiu@starfivetech.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230922092848.72664-1-william.qiu@starfivetech.com> References: <20230922092848.72664-1-william.qiu@starfivetech.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [171.223.208.138] X-ClientProxiedBy: EXCAS061.cuchost.com (172.16.6.21) To EXMBX168.cuchost.com (172.16.6.78) X-YovoleRuleAgent: yovoleflag Content-Transfer-Encoding: 8BIT X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on morse.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (morse.vger.email [0.0.0.0]); Fri, 22 Sep 2023 02:29:26 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1777729707368272793 X-GMAIL-MSGID: 1777729707368272793 |
Series |
StarFive's Pulse Width Modulation driver support
|
|
Commit Message
William Qiu
Sept. 22, 2023, 9:28 a.m. UTC
Add Pulse Width Modulation driver support for StarFive JH7100 and JH7110 SoC. Co-developed-by: Hal Feng <hal.feng@starfivetech.com> Signed-off-by: Hal Feng <hal.feng@starfivetech.com> Signed-off-by: William Qiu <william.qiu@starfivetech.com> --- MAINTAINERS | 7 ++ drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100644 drivers/pwm/pwm-starfive.c
Comments
William Qiu wrote: > Add Pulse Width Modulation driver support for StarFive > JH7100 and JH7110 SoC. > > Co-developed-by: Hal Feng <hal.feng@starfivetech.com> > Signed-off-by: Hal Feng <hal.feng@starfivetech.com> > Signed-off-by: William Qiu <william.qiu@starfivetech.com> > --- > MAINTAINERS | 7 ++ > drivers/pwm/Kconfig | 9 ++ > drivers/pwm/Makefile | 1 + > drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ > 4 files changed, 207 insertions(+) > create mode 100644 drivers/pwm/pwm-starfive.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index bf0f54c24f81..bc2155bd2712 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* > F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h > F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h > > +STARFIVE JH71X0 PWM DRIVERS > +M: William Qiu <william.qiu@starfivetech.com> > +M: Hal Feng <hal.feng@starfivetech.com> > +S: Supported > +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml > +F: drivers/pwm/pwm-starfive-ptc.c > + > STARFIVE JH71X0 RESET CONTROLLER DRIVERS > M: Emil Renner Berthing <kernel@esmil.dk> > M: Hal Feng <hal.feng@starfivetech.com> > diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig > index 8ebcddf91f7b..e2ee0169f6e4 100644 > --- a/drivers/pwm/Kconfig > +++ b/drivers/pwm/Kconfig > @@ -569,6 +569,15 @@ config PWM_SPRD > To compile this driver as a module, choose M here: the module > will be called pwm-sprd. > > +config PWM_STARFIVE > + tristate "StarFive PWM support" > + depends on ARCH_STARFIVE || COMPILE_TEST > + help > + Generic PWM framework driver for StarFive SoCs. > + > + To compile this driver as a module, choose M here: the module > + will be called pwm-starfive. > + > config PWM_STI > tristate "STiH4xx PWM support" > depends on ARCH_STI || COMPILE_TEST > diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile > index c822389c2a24..93b954376873 100644 > --- a/drivers/pwm/Makefile > +++ b/drivers/pwm/Makefile > @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o > obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o > obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o > obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o > +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o > obj-$(CONFIG_PWM_STI) += pwm-sti.o > obj-$(CONFIG_PWM_STM32) += pwm-stm32.o > obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o > diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c Hi William, You never answered my questions about what PTC is short for and if there are other PWMs on the JH7110. You just removed -ptc from the name of this file.. > new file mode 100644 > index 000000000000..d390349fc95d > --- /dev/null > +++ b/drivers/pwm/pwm-starfive.c > @@ -0,0 +1,190 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * PWM driver for the StarFive JH71x0 SoC > + * > + * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. > + */ > + > +#include <linux/clk.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/pwm.h> > +#include <linux/reset.h> > +#include <linux/slab.h> > + > +/* Access PTC register (CNTR, HRC, LRC and CTRL) */ > +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + (((N) > 3) ? \ > + (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) > +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) > +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) > +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) > +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) ..but these defines > + > +/* PTC_RPTC_CTRL register bits*/ > +#define PTC_EN BIT(0) > +#define PTC_ECLK BIT(1) > +#define PTC_NEC BIT(2) > +#define PTC_OE BIT(3) > +#define PTC_SIGNLE BIT(4) > +#define PTC_INTE BIT(5) > +#define PTC_INT BIT(6) > +#define PTC_CNTRRST BIT(7) > +#define PTC_CAPTE BIT(8) ..and these defines are still prefixed with *PTC where I'd expect something like STARFIVE_PWM_, and below structs and function names are also still using starfive_pwm_ptc_ where I'd expect starfive_pwm_. Please be consistant in your naming. > +struct starfive_pwm_ptc_device { > + struct pwm_chip chip; > + struct clk *clk; > + struct reset_control *rst; > + void __iomem *regs; > + u32 clk_rate; /* PWM APB clock frequency */ > +}; > + > +static inline struct starfive_pwm_ptc_device * > +chip_to_starfive_ptc(struct pwm_chip *chip) > + > +{ > + return container_of(chip, struct starfive_pwm_ptc_device, chip); > +} > + > +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, > + struct pwm_device *dev, > + struct pwm_state *state) > +{ > + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); > + u32 period_data, duty_data, ctrl_data; > + > + period_data = readl(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); > + duty_data = readl(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); > + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > + > + state->period = DIV_ROUND_CLOSEST_ULL((u64)period_data * NSEC_PER_SEC, pwm->clk_rate); > + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_data * NSEC_PER_SEC, pwm->clk_rate); > + state->polarity = PWM_POLARITY_INVERSED; > + state->enabled = (ctrl_data & PTC_EN) ? true : false; > + > + return 0; > +} > + > +static int starfive_pwm_ptc_apply(struct pwm_chip *chip, > + struct pwm_device *dev, > + const struct pwm_state *state) > +{ > + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); > + u32 period_data, duty_data, ctrl_data = 0; > + > + if (state->polarity != PWM_POLARITY_INVERSED) > + return -EINVAL; > + > + period_data = DIV_ROUND_CLOSEST_ULL(state->period * pwm->clk_rate, > + NSEC_PER_SEC); > + duty_data = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pwm->clk_rate, > + NSEC_PER_SEC); > + > + writel(period_data, REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); > + writel(duty_data, REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); > + writel(0, REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm)); > + > + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > + if (state->enabled) > + writel(ctrl_data | PTC_EN | PTC_OE, REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > + else > + writel(ctrl_data & ~(PTC_EN | PTC_OE), REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > + > + return 0; > +} > + > +static const struct pwm_ops starfive_pwm_ptc_ops = { > + .get_state = starfive_pwm_ptc_get_state, > + .apply = starfive_pwm_ptc_apply, > + .owner = THIS_MODULE, > +}; > + > +static int starfive_pwm_ptc_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct starfive_pwm_ptc_device *pwm; > + struct pwm_chip *chip; > + int ret; > + > + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); > + if (!pwm) > + return -ENOMEM; > + > + chip = &pwm->chip; > + chip->dev = dev; > + chip->ops = &starfive_pwm_ptc_ops; > + chip->npwm = 8; > + chip->of_pwm_n_cells = 3; > + > + pwm->regs = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(pwm->regs)) > + return dev_err_probe(dev, PTR_ERR(pwm->regs), > + "Unable to map IO resources\n"); > + > + pwm->clk = devm_clk_get_enabled(dev, NULL); > + if (IS_ERR(pwm->clk)) > + return dev_err_probe(dev, PTR_ERR(pwm->clk), > + "Unable to get pwm's clock\n"); > + > + pwm->rst = devm_reset_control_get_exclusive(dev, NULL); > + if (IS_ERR(pwm->rst)) > + return dev_err_probe(dev, PTR_ERR(pwm->rst), > + "Unable to get pwm's reset\n"); > + > + ret = reset_control_deassert(pwm->rst); > + if (ret) { > + dev_err(dev, "Failed to enable clock for pwm: %d\n", ret); > + return ret; > + } > + > + pwm->clk_rate = clk_get_rate(pwm->clk); > + if (pwm->clk_rate <= 0) { > + dev_warn(dev, "Failed to get APB clock rate\n"); > + return -EINVAL; > + } > + > + ret = devm_pwmchip_add(dev, chip); > + if (ret < 0) { > + dev_err(dev, "Cannot register PTC: %d\n", ret); > + clk_disable_unprepare(pwm->clk); > + reset_control_assert(pwm->rst); > + return ret; > + } > + > + platform_set_drvdata(pdev, pwm); > + > + return 0; > +} > + > +static int starfive_pwm_ptc_remove(struct platform_device *dev) > +{ > + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); > + > + reset_control_assert(pwm->rst); > + clk_disable_unprepare(pwm->clk); > + > + return 0; > +} > + > +static const struct of_device_id starfive_pwm_ptc_of_match[] = { > + { .compatible = "starfive,jh7100-pwm" }, > + { .compatible = "starfive,jh7110-pwm" }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); > + > +static struct platform_driver starfive_pwm_ptc_driver = { > + .probe = starfive_pwm_ptc_probe, > + .remove = starfive_pwm_ptc_remove, > + .driver = { > + .name = "pwm-starfive-ptc", Here > + .of_match_table = starfive_pwm_ptc_of_match, > + }, > +}; > +module_platform_driver(starfive_pwm_ptc_driver); > + > +MODULE_AUTHOR("Jieqin Chen"); > +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); > +MODULE_DESCRIPTION("StarFive PWM PTC driver"); ..and here you're also still calling the driver PTC without explaining why. > +MODULE_LICENSE("GPL"); > -- > 2.34.1 >
On 2023/9/23 20:08, Emil Renner Berthing wrote: > William Qiu wrote: >> Add Pulse Width Modulation driver support for StarFive >> JH7100 and JH7110 SoC. >> >> Co-developed-by: Hal Feng <hal.feng@starfivetech.com> >> Signed-off-by: Hal Feng <hal.feng@starfivetech.com> >> Signed-off-by: William Qiu <william.qiu@starfivetech.com> >> --- >> MAINTAINERS | 7 ++ >> drivers/pwm/Kconfig | 9 ++ >> drivers/pwm/Makefile | 1 + >> drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ >> 4 files changed, 207 insertions(+) >> create mode 100644 drivers/pwm/pwm-starfive.c >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index bf0f54c24f81..bc2155bd2712 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* >> F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h >> F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h >> >> +STARFIVE JH71X0 PWM DRIVERS >> +M: William Qiu <william.qiu@starfivetech.com> >> +M: Hal Feng <hal.feng@starfivetech.com> >> +S: Supported >> +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml >> +F: drivers/pwm/pwm-starfive-ptc.c >> + >> STARFIVE JH71X0 RESET CONTROLLER DRIVERS >> M: Emil Renner Berthing <kernel@esmil.dk> >> M: Hal Feng <hal.feng@starfivetech.com> >> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig >> index 8ebcddf91f7b..e2ee0169f6e4 100644 >> --- a/drivers/pwm/Kconfig >> +++ b/drivers/pwm/Kconfig >> @@ -569,6 +569,15 @@ config PWM_SPRD >> To compile this driver as a module, choose M here: the module >> will be called pwm-sprd. >> >> +config PWM_STARFIVE >> + tristate "StarFive PWM support" >> + depends on ARCH_STARFIVE || COMPILE_TEST >> + help >> + Generic PWM framework driver for StarFive SoCs. >> + >> + To compile this driver as a module, choose M here: the module >> + will be called pwm-starfive. >> + >> config PWM_STI >> tristate "STiH4xx PWM support" >> depends on ARCH_STI || COMPILE_TEST >> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile >> index c822389c2a24..93b954376873 100644 >> --- a/drivers/pwm/Makefile >> +++ b/drivers/pwm/Makefile >> @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o >> obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o >> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o >> obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o >> +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o >> obj-$(CONFIG_PWM_STI) += pwm-sti.o >> obj-$(CONFIG_PWM_STM32) += pwm-stm32.o >> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o >> diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c > > Hi William, > > You never answered my questions about what PTC is short for and if there are > other PWMs on the JH7110. You just removed -ptc from the name of this file.. > Hi Emil, The PTC, short for PWM/TIMER/CONUTER, comes from OpenCore's ip, but only PWM mode is used in the JH7110. So the register still has the word "PTC". s the best way to change all the prefix to STARFIVE? Best regards, William >> new file mode 100644 >> index 000000000000..d390349fc95d >> --- /dev/null >> +++ b/drivers/pwm/pwm-starfive.c >> @@ -0,0 +1,190 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * PWM driver for the StarFive JH71x0 SoC >> + * >> + * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. >> + */ >> + >> +#include <linux/clk.h> >> +#include <linux/io.h> >> +#include <linux/module.h> >> +#include <linux/platform_device.h> >> +#include <linux/pwm.h> >> +#include <linux/reset.h> >> +#include <linux/slab.h> >> + >> +/* Access PTC register (CNTR, HRC, LRC and CTRL) */ >> +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + (((N) > 3) ? \ >> + (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) >> +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) >> +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) >> +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) >> +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) > > ..but these defines > >> + >> +/* PTC_RPTC_CTRL register bits*/ >> +#define PTC_EN BIT(0) >> +#define PTC_ECLK BIT(1) >> +#define PTC_NEC BIT(2) >> +#define PTC_OE BIT(3) >> +#define PTC_SIGNLE BIT(4) >> +#define PTC_INTE BIT(5) >> +#define PTC_INT BIT(6) >> +#define PTC_CNTRRST BIT(7) >> +#define PTC_CAPTE BIT(8) > > ..and these defines are still prefixed with *PTC where I'd expect something like > STARFIVE_PWM_, and below structs and function names are also still > using starfive_pwm_ptc_ > where I'd expect starfive_pwm_. Please be consistant in your naming. > >> +struct starfive_pwm_ptc_device { >> + struct pwm_chip chip; >> + struct clk *clk; >> + struct reset_control *rst; >> + void __iomem *regs; >> + u32 clk_rate; /* PWM APB clock frequency */ >> +}; >> + >> +static inline struct starfive_pwm_ptc_device * >> +chip_to_starfive_ptc(struct pwm_chip *chip) >> + >> +{ >> + return container_of(chip, struct starfive_pwm_ptc_device, chip); >> +} >> + >> +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, >> + struct pwm_device *dev, >> + struct pwm_state *state) >> +{ >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); >> + u32 period_data, duty_data, ctrl_data; >> + >> + period_data = readl(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); >> + duty_data = readl(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> + >> + state->period = DIV_ROUND_CLOSEST_ULL((u64)period_data * NSEC_PER_SEC, pwm->clk_rate); >> + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_data * NSEC_PER_SEC, pwm->clk_rate); >> + state->polarity = PWM_POLARITY_INVERSED; >> + state->enabled = (ctrl_data & PTC_EN) ? true : false; >> + >> + return 0; >> +} >> + >> +static int starfive_pwm_ptc_apply(struct pwm_chip *chip, >> + struct pwm_device *dev, >> + const struct pwm_state *state) >> +{ >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); >> + u32 period_data, duty_data, ctrl_data = 0; >> + >> + if (state->polarity != PWM_POLARITY_INVERSED) >> + return -EINVAL; >> + >> + period_data = DIV_ROUND_CLOSEST_ULL(state->period * pwm->clk_rate, >> + NSEC_PER_SEC); >> + duty_data = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pwm->clk_rate, >> + NSEC_PER_SEC); >> + >> + writel(period_data, REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); >> + writel(duty_data, REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); >> + writel(0, REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm)); >> + >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> + if (state->enabled) >> + writel(ctrl_data | PTC_EN | PTC_OE, REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> + else >> + writel(ctrl_data & ~(PTC_EN | PTC_OE), REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> + >> + return 0; >> +} >> + >> +static const struct pwm_ops starfive_pwm_ptc_ops = { >> + .get_state = starfive_pwm_ptc_get_state, >> + .apply = starfive_pwm_ptc_apply, >> + .owner = THIS_MODULE, >> +}; >> + >> +static int starfive_pwm_ptc_probe(struct platform_device *pdev) >> +{ >> + struct device *dev = &pdev->dev; >> + struct starfive_pwm_ptc_device *pwm; >> + struct pwm_chip *chip; >> + int ret; >> + >> + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); >> + if (!pwm) >> + return -ENOMEM; >> + >> + chip = &pwm->chip; >> + chip->dev = dev; >> + chip->ops = &starfive_pwm_ptc_ops; >> + chip->npwm = 8; >> + chip->of_pwm_n_cells = 3; >> + >> + pwm->regs = devm_platform_ioremap_resource(pdev, 0); >> + if (IS_ERR(pwm->regs)) >> + return dev_err_probe(dev, PTR_ERR(pwm->regs), >> + "Unable to map IO resources\n"); >> + >> + pwm->clk = devm_clk_get_enabled(dev, NULL); >> + if (IS_ERR(pwm->clk)) >> + return dev_err_probe(dev, PTR_ERR(pwm->clk), >> + "Unable to get pwm's clock\n"); >> + >> + pwm->rst = devm_reset_control_get_exclusive(dev, NULL); >> + if (IS_ERR(pwm->rst)) >> + return dev_err_probe(dev, PTR_ERR(pwm->rst), >> + "Unable to get pwm's reset\n"); >> + >> + ret = reset_control_deassert(pwm->rst); >> + if (ret) { >> + dev_err(dev, "Failed to enable clock for pwm: %d\n", ret); >> + return ret; >> + } >> + >> + pwm->clk_rate = clk_get_rate(pwm->clk); >> + if (pwm->clk_rate <= 0) { >> + dev_warn(dev, "Failed to get APB clock rate\n"); >> + return -EINVAL; >> + } >> + >> + ret = devm_pwmchip_add(dev, chip); >> + if (ret < 0) { >> + dev_err(dev, "Cannot register PTC: %d\n", ret); >> + clk_disable_unprepare(pwm->clk); >> + reset_control_assert(pwm->rst); >> + return ret; >> + } >> + >> + platform_set_drvdata(pdev, pwm); >> + >> + return 0; >> +} >> + >> +static int starfive_pwm_ptc_remove(struct platform_device *dev) >> +{ >> + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); >> + >> + reset_control_assert(pwm->rst); >> + clk_disable_unprepare(pwm->clk); >> + >> + return 0; >> +} >> + >> +static const struct of_device_id starfive_pwm_ptc_of_match[] = { >> + { .compatible = "starfive,jh7100-pwm" }, >> + { .compatible = "starfive,jh7110-pwm" }, >> + { /* sentinel */ } >> +}; >> +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); >> + >> +static struct platform_driver starfive_pwm_ptc_driver = { >> + .probe = starfive_pwm_ptc_probe, >> + .remove = starfive_pwm_ptc_remove, >> + .driver = { >> + .name = "pwm-starfive-ptc", > > Here > >> + .of_match_table = starfive_pwm_ptc_of_match, >> + }, >> +}; >> +module_platform_driver(starfive_pwm_ptc_driver); >> + >> +MODULE_AUTHOR("Jieqin Chen"); >> +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); >> +MODULE_DESCRIPTION("StarFive PWM PTC driver"); > > ..and here you're also still calling the driver PTC without explaining why. > >> +MODULE_LICENSE("GPL"); >> -- >> 2.34.1 >>
William Qiu wrote: > > > On 2023/9/23 20:08, Emil Renner Berthing wrote: > > William Qiu wrote: > >> Add Pulse Width Modulation driver support for StarFive > >> JH7100 and JH7110 SoC. > >> > >> Co-developed-by: Hal Feng <hal.feng@starfivetech.com> > >> Signed-off-by: Hal Feng <hal.feng@starfivetech.com> > >> Signed-off-by: William Qiu <william.qiu@starfivetech.com> > >> --- > >> MAINTAINERS | 7 ++ > >> drivers/pwm/Kconfig | 9 ++ > >> drivers/pwm/Makefile | 1 + > >> drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ > >> 4 files changed, 207 insertions(+) > >> create mode 100644 drivers/pwm/pwm-starfive.c > >> > >> diff --git a/MAINTAINERS b/MAINTAINERS > >> index bf0f54c24f81..bc2155bd2712 100644 > >> --- a/MAINTAINERS > >> +++ b/MAINTAINERS > >> @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* > >> F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h > >> F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h > >> > >> +STARFIVE JH71X0 PWM DRIVERS > >> +M: William Qiu <william.qiu@starfivetech.com> > >> +M: Hal Feng <hal.feng@starfivetech.com> > >> +S: Supported > >> +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml > >> +F: drivers/pwm/pwm-starfive-ptc.c > >> + > >> STARFIVE JH71X0 RESET CONTROLLER DRIVERS > >> M: Emil Renner Berthing <kernel@esmil.dk> > >> M: Hal Feng <hal.feng@starfivetech.com> > >> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig > >> index 8ebcddf91f7b..e2ee0169f6e4 100644 > >> --- a/drivers/pwm/Kconfig > >> +++ b/drivers/pwm/Kconfig > >> @@ -569,6 +569,15 @@ config PWM_SPRD > >> To compile this driver as a module, choose M here: the module > >> will be called pwm-sprd. > >> > >> +config PWM_STARFIVE > >> + tristate "StarFive PWM support" > >> + depends on ARCH_STARFIVE || COMPILE_TEST > >> + help > >> + Generic PWM framework driver for StarFive SoCs. > >> + > >> + To compile this driver as a module, choose M here: the module > >> + will be called pwm-starfive. > >> + > >> config PWM_STI > >> tristate "STiH4xx PWM support" > >> depends on ARCH_STI || COMPILE_TEST > >> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile > >> index c822389c2a24..93b954376873 100644 > >> --- a/drivers/pwm/Makefile > >> +++ b/drivers/pwm/Makefile > >> @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o > >> obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o > >> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o > >> obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o > >> +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o > >> obj-$(CONFIG_PWM_STI) += pwm-sti.o > >> obj-$(CONFIG_PWM_STM32) += pwm-stm32.o > >> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o > >> diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c > > > > Hi William, > > > > You never answered my questions about what PTC is short for and if there are > > other PWMs on the JH7110. You just removed -ptc from the name of this file.. > > > Hi Emil, > > The PTC, short for PWM/TIMER/CONUTER, comes from OpenCore's ip, but only PWM > mode is used in the JH7110. So the register still has the word "PTC". > s the best way to change all the prefix to STARFIVE? I see. Yeah, since you're only using the P from PTC the PTC name doesn't make a lot of sense anymore. I'd just call this whole driver STARFIVE_PWM_/starfive_pwm_ consistently. > > Best regards, > William > >> new file mode 100644 > >> index 000000000000..d390349fc95d > >> --- /dev/null > >> +++ b/drivers/pwm/pwm-starfive.c > >> @@ -0,0 +1,190 @@ > >> +// SPDX-License-Identifier: GPL-2.0 > >> +/* > >> + * PWM driver for the StarFive JH71x0 SoC > >> + * > >> + * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. > >> + */ > >> + > >> +#include <linux/clk.h> > >> +#include <linux/io.h> > >> +#include <linux/module.h> > >> +#include <linux/platform_device.h> > >> +#include <linux/pwm.h> > >> +#include <linux/reset.h> > >> +#include <linux/slab.h> > >> + > >> +/* Access PTC register (CNTR, HRC, LRC and CTRL) */ > >> +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + (((N) > 3) ? \ > >> + (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) > >> +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) > >> +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) > >> +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) > >> +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) > > > > ..but these defines > > > >> + > >> +/* PTC_RPTC_CTRL register bits*/ > >> +#define PTC_EN BIT(0) > >> +#define PTC_ECLK BIT(1) > >> +#define PTC_NEC BIT(2) > >> +#define PTC_OE BIT(3) > >> +#define PTC_SIGNLE BIT(4) > >> +#define PTC_INTE BIT(5) > >> +#define PTC_INT BIT(6) > >> +#define PTC_CNTRRST BIT(7) > >> +#define PTC_CAPTE BIT(8) > > > > ..and these defines are still prefixed with *PTC where I'd expect something like > > STARFIVE_PWM_, and below structs and function names are also still > > using starfive_pwm_ptc_ > > where I'd expect starfive_pwm_. Please be consistant in your naming. > > > >> +struct starfive_pwm_ptc_device { > >> + struct pwm_chip chip; > >> + struct clk *clk; > >> + struct reset_control *rst; > >> + void __iomem *regs; > >> + u32 clk_rate; /* PWM APB clock frequency */ > >> +}; > >> + > >> +static inline struct starfive_pwm_ptc_device * > >> +chip_to_starfive_ptc(struct pwm_chip *chip) > >> + > >> +{ > >> + return container_of(chip, struct starfive_pwm_ptc_device, chip); > >> +} > >> + > >> +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, > >> + struct pwm_device *dev, > >> + struct pwm_state *state) > >> +{ > >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); > >> + u32 period_data, duty_data, ctrl_data; > >> + > >> + period_data = readl(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); > >> + duty_data = readl(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); > >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > >> + > >> + state->period = DIV_ROUND_CLOSEST_ULL((u64)period_data * NSEC_PER_SEC, pwm->clk_rate); > >> + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_data * NSEC_PER_SEC, pwm->clk_rate); > >> + state->polarity = PWM_POLARITY_INVERSED; > >> + state->enabled = (ctrl_data & PTC_EN) ? true : false; > >> + > >> + return 0; > >> +} > >> + > >> +static int starfive_pwm_ptc_apply(struct pwm_chip *chip, > >> + struct pwm_device *dev, > >> + const struct pwm_state *state) > >> +{ > >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); > >> + u32 period_data, duty_data, ctrl_data = 0; > >> + > >> + if (state->polarity != PWM_POLARITY_INVERSED) > >> + return -EINVAL; > >> + > >> + period_data = DIV_ROUND_CLOSEST_ULL(state->period * pwm->clk_rate, > >> + NSEC_PER_SEC); > >> + duty_data = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pwm->clk_rate, > >> + NSEC_PER_SEC); > >> + > >> + writel(period_data, REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); > >> + writel(duty_data, REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); > >> + writel(0, REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm)); > >> + > >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > >> + if (state->enabled) > >> + writel(ctrl_data | PTC_EN | PTC_OE, REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > >> + else > >> + writel(ctrl_data & ~(PTC_EN | PTC_OE), REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); > >> + > >> + return 0; > >> +} > >> + > >> +static const struct pwm_ops starfive_pwm_ptc_ops = { > >> + .get_state = starfive_pwm_ptc_get_state, > >> + .apply = starfive_pwm_ptc_apply, > >> + .owner = THIS_MODULE, > >> +}; > >> + > >> +static int starfive_pwm_ptc_probe(struct platform_device *pdev) > >> +{ > >> + struct device *dev = &pdev->dev; > >> + struct starfive_pwm_ptc_device *pwm; > >> + struct pwm_chip *chip; > >> + int ret; > >> + > >> + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); > >> + if (!pwm) > >> + return -ENOMEM; > >> + > >> + chip = &pwm->chip; > >> + chip->dev = dev; > >> + chip->ops = &starfive_pwm_ptc_ops; > >> + chip->npwm = 8; > >> + chip->of_pwm_n_cells = 3; > >> + > >> + pwm->regs = devm_platform_ioremap_resource(pdev, 0); > >> + if (IS_ERR(pwm->regs)) > >> + return dev_err_probe(dev, PTR_ERR(pwm->regs), > >> + "Unable to map IO resources\n"); > >> + > >> + pwm->clk = devm_clk_get_enabled(dev, NULL); > >> + if (IS_ERR(pwm->clk)) > >> + return dev_err_probe(dev, PTR_ERR(pwm->clk), > >> + "Unable to get pwm's clock\n"); > >> + > >> + pwm->rst = devm_reset_control_get_exclusive(dev, NULL); > >> + if (IS_ERR(pwm->rst)) > >> + return dev_err_probe(dev, PTR_ERR(pwm->rst), > >> + "Unable to get pwm's reset\n"); > >> + > >> + ret = reset_control_deassert(pwm->rst); > >> + if (ret) { > >> + dev_err(dev, "Failed to enable clock for pwm: %d\n", ret); > >> + return ret; > >> + } > >> + > >> + pwm->clk_rate = clk_get_rate(pwm->clk); > >> + if (pwm->clk_rate <= 0) { > >> + dev_warn(dev, "Failed to get APB clock rate\n"); > >> + return -EINVAL; > >> + } > >> + > >> + ret = devm_pwmchip_add(dev, chip); > >> + if (ret < 0) { > >> + dev_err(dev, "Cannot register PTC: %d\n", ret); > >> + clk_disable_unprepare(pwm->clk); > >> + reset_control_assert(pwm->rst); > >> + return ret; > >> + } > >> + > >> + platform_set_drvdata(pdev, pwm); > >> + > >> + return 0; > >> +} > >> + > >> +static int starfive_pwm_ptc_remove(struct platform_device *dev) > >> +{ > >> + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); > >> + > >> + reset_control_assert(pwm->rst); > >> + clk_disable_unprepare(pwm->clk); > >> + > >> + return 0; > >> +} > >> + > >> +static const struct of_device_id starfive_pwm_ptc_of_match[] = { > >> + { .compatible = "starfive,jh7100-pwm" }, > >> + { .compatible = "starfive,jh7110-pwm" }, > >> + { /* sentinel */ } > >> +}; > >> +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); > >> + > >> +static struct platform_driver starfive_pwm_ptc_driver = { > >> + .probe = starfive_pwm_ptc_probe, > >> + .remove = starfive_pwm_ptc_remove, > >> + .driver = { > >> + .name = "pwm-starfive-ptc", > > > > Here > > > >> + .of_match_table = starfive_pwm_ptc_of_match, > >> + }, > >> +}; > >> +module_platform_driver(starfive_pwm_ptc_driver); > >> + > >> +MODULE_AUTHOR("Jieqin Chen"); > >> +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); > >> +MODULE_DESCRIPTION("StarFive PWM PTC driver"); > > > > ..and here you're also still calling the driver PTC without explaining why. > > > >> +MODULE_LICENSE("GPL"); > >> -- > >> 2.34.1 > >>
On 2023/9/25 18:31, Emil Renner Berthing wrote: > William Qiu wrote: >> >> >> On 2023/9/23 20:08, Emil Renner Berthing wrote: >> > William Qiu wrote: >> >> Add Pulse Width Modulation driver support for StarFive >> >> JH7100 and JH7110 SoC. >> >> >> >> Co-developed-by: Hal Feng <hal.feng@starfivetech.com> >> >> Signed-off-by: Hal Feng <hal.feng@starfivetech.com> >> >> Signed-off-by: William Qiu <william.qiu@starfivetech.com> >> >> --- >> >> MAINTAINERS | 7 ++ >> >> drivers/pwm/Kconfig | 9 ++ >> >> drivers/pwm/Makefile | 1 + >> >> drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ >> >> 4 files changed, 207 insertions(+) >> >> create mode 100644 drivers/pwm/pwm-starfive.c >> >> >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> >> index bf0f54c24f81..bc2155bd2712 100644 >> >> --- a/MAINTAINERS >> >> +++ b/MAINTAINERS >> >> @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* >> >> F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h >> >> F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h >> >> >> >> +STARFIVE JH71X0 PWM DRIVERS >> >> +M: William Qiu <william.qiu@starfivetech.com> >> >> +M: Hal Feng <hal.feng@starfivetech.com> >> >> +S: Supported >> >> +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml >> >> +F: drivers/pwm/pwm-starfive-ptc.c >> >> + >> >> STARFIVE JH71X0 RESET CONTROLLER DRIVERS >> >> M: Emil Renner Berthing <kernel@esmil.dk> >> >> M: Hal Feng <hal.feng@starfivetech.com> >> >> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig >> >> index 8ebcddf91f7b..e2ee0169f6e4 100644 >> >> --- a/drivers/pwm/Kconfig >> >> +++ b/drivers/pwm/Kconfig >> >> @@ -569,6 +569,15 @@ config PWM_SPRD >> >> To compile this driver as a module, choose M here: the module >> >> will be called pwm-sprd. >> >> >> >> +config PWM_STARFIVE >> >> + tristate "StarFive PWM support" >> >> + depends on ARCH_STARFIVE || COMPILE_TEST >> >> + help >> >> + Generic PWM framework driver for StarFive SoCs. >> >> + >> >> + To compile this driver as a module, choose M here: the module >> >> + will be called pwm-starfive. >> >> + >> >> config PWM_STI >> >> tristate "STiH4xx PWM support" >> >> depends on ARCH_STI || COMPILE_TEST >> >> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile >> >> index c822389c2a24..93b954376873 100644 >> >> --- a/drivers/pwm/Makefile >> >> +++ b/drivers/pwm/Makefile >> >> @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o >> >> obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o >> >> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o >> >> obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o >> >> +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o >> >> obj-$(CONFIG_PWM_STI) += pwm-sti.o >> >> obj-$(CONFIG_PWM_STM32) += pwm-stm32.o >> >> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o >> >> diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c >> > >> > Hi William, >> > >> > You never answered my questions about what PTC is short for and if there are >> > other PWMs on the JH7110. You just removed -ptc from the name of this file.. >> > >> Hi Emil, >> >> The PTC, short for PWM/TIMER/CONUTER, comes from OpenCore's ip, but only PWM >> mode is used in the JH7110. So the register still has the word "PTC". >> s the best way to change all the prefix to STARFIVE? > > I see. Yeah, since you're only using the P from PTC the PTC name doesn't make a > lot of sense anymore. I'd just call this whole driver > STARFIVE_PWM_/starfive_pwm_ consistently. > I see, I'll update it in next version. >> >> Best regards, >> William >> >> new file mode 100644 >> >> index 000000000000..d390349fc95d >> >> --- /dev/null >> >> +++ b/drivers/pwm/pwm-starfive.c >> >> @@ -0,0 +1,190 @@ >> >> +// SPDX-License-Identifier: GPL-2.0 >> >> +/* >> >> + * PWM driver for the StarFive JH71x0 SoC >> >> + * >> >> + * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. >> >> + */ >> >> + >> >> +#include <linux/clk.h> >> >> +#include <linux/io.h> >> >> +#include <linux/module.h> >> >> +#include <linux/platform_device.h> >> >> +#include <linux/pwm.h> >> >> +#include <linux/reset.h> >> >> +#include <linux/slab.h> >> >> + >> >> +/* Access PTC register (CNTR, HRC, LRC and CTRL) */ >> >> +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + (((N) > 3) ? \ >> >> + (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) >> >> +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) >> >> +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) >> >> +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) >> >> +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) >> > >> > ..but these defines >> > >> >> + >> >> +/* PTC_RPTC_CTRL register bits*/ >> >> +#define PTC_EN BIT(0) >> >> +#define PTC_ECLK BIT(1) >> >> +#define PTC_NEC BIT(2) >> >> +#define PTC_OE BIT(3) >> >> +#define PTC_SIGNLE BIT(4) >> >> +#define PTC_INTE BIT(5) >> >> +#define PTC_INT BIT(6) >> >> +#define PTC_CNTRRST BIT(7) >> >> +#define PTC_CAPTE BIT(8) >> > >> > ..and these defines are still prefixed with *PTC where I'd expect something like >> > STARFIVE_PWM_, and below structs and function names are also still >> > using starfive_pwm_ptc_ >> > where I'd expect starfive_pwm_. Please be consistant in your naming. >> > >> >> +struct starfive_pwm_ptc_device { >> >> + struct pwm_chip chip; >> >> + struct clk *clk; >> >> + struct reset_control *rst; >> >> + void __iomem *regs; >> >> + u32 clk_rate; /* PWM APB clock frequency */ >> >> +}; >> >> + >> >> +static inline struct starfive_pwm_ptc_device * >> >> +chip_to_starfive_ptc(struct pwm_chip *chip) >> >> + >> >> +{ >> >> + return container_of(chip, struct starfive_pwm_ptc_device, chip); >> >> +} >> >> + >> >> +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, >> >> + struct pwm_device *dev, >> >> + struct pwm_state *state) >> >> +{ >> >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); >> >> + u32 period_data, duty_data, ctrl_data; >> >> + >> >> + period_data = readl(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); >> >> + duty_data = readl(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); >> >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> >> + >> >> + state->period = DIV_ROUND_CLOSEST_ULL((u64)period_data * NSEC_PER_SEC, pwm->clk_rate); >> >> + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_data * NSEC_PER_SEC, pwm->clk_rate); >> >> + state->polarity = PWM_POLARITY_INVERSED; >> >> + state->enabled = (ctrl_data & PTC_EN) ? true : false; >> >> + >> >> + return 0; >> >> +} >> >> + >> >> +static int starfive_pwm_ptc_apply(struct pwm_chip *chip, >> >> + struct pwm_device *dev, >> >> + const struct pwm_state *state) >> >> +{ >> >> + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); >> >> + u32 period_data, duty_data, ctrl_data = 0; >> >> + >> >> + if (state->polarity != PWM_POLARITY_INVERSED) >> >> + return -EINVAL; >> >> + >> >> + period_data = DIV_ROUND_CLOSEST_ULL(state->period * pwm->clk_rate, >> >> + NSEC_PER_SEC); >> >> + duty_data = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pwm->clk_rate, >> >> + NSEC_PER_SEC); >> >> + >> >> + writel(period_data, REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); >> >> + writel(duty_data, REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); >> >> + writel(0, REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm)); >> >> + >> >> + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> >> + if (state->enabled) >> >> + writel(ctrl_data | PTC_EN | PTC_OE, REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> >> + else >> >> + writel(ctrl_data & ~(PTC_EN | PTC_OE), REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); >> >> + >> >> + return 0; >> >> +} >> >> + >> >> +static const struct pwm_ops starfive_pwm_ptc_ops = { >> >> + .get_state = starfive_pwm_ptc_get_state, >> >> + .apply = starfive_pwm_ptc_apply, >> >> + .owner = THIS_MODULE, >> >> +}; >> >> + >> >> +static int starfive_pwm_ptc_probe(struct platform_device *pdev) >> >> +{ >> >> + struct device *dev = &pdev->dev; >> >> + struct starfive_pwm_ptc_device *pwm; >> >> + struct pwm_chip *chip; >> >> + int ret; >> >> + >> >> + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); >> >> + if (!pwm) >> >> + return -ENOMEM; >> >> + >> >> + chip = &pwm->chip; >> >> + chip->dev = dev; >> >> + chip->ops = &starfive_pwm_ptc_ops; >> >> + chip->npwm = 8; >> >> + chip->of_pwm_n_cells = 3; >> >> + >> >> + pwm->regs = devm_platform_ioremap_resource(pdev, 0); >> >> + if (IS_ERR(pwm->regs)) >> >> + return dev_err_probe(dev, PTR_ERR(pwm->regs), >> >> + "Unable to map IO resources\n"); >> >> + >> >> + pwm->clk = devm_clk_get_enabled(dev, NULL); >> >> + if (IS_ERR(pwm->clk)) >> >> + return dev_err_probe(dev, PTR_ERR(pwm->clk), >> >> + "Unable to get pwm's clock\n"); >> >> + >> >> + pwm->rst = devm_reset_control_get_exclusive(dev, NULL); >> >> + if (IS_ERR(pwm->rst)) >> >> + return dev_err_probe(dev, PTR_ERR(pwm->rst), >> >> + "Unable to get pwm's reset\n"); >> >> + >> >> + ret = reset_control_deassert(pwm->rst); >> >> + if (ret) { >> >> + dev_err(dev, "Failed to enable clock for pwm: %d\n", ret); >> >> + return ret; >> >> + } >> >> + >> >> + pwm->clk_rate = clk_get_rate(pwm->clk); >> >> + if (pwm->clk_rate <= 0) { >> >> + dev_warn(dev, "Failed to get APB clock rate\n"); >> >> + return -EINVAL; >> >> + } >> >> + >> >> + ret = devm_pwmchip_add(dev, chip); >> >> + if (ret < 0) { >> >> + dev_err(dev, "Cannot register PTC: %d\n", ret); >> >> + clk_disable_unprepare(pwm->clk); >> >> + reset_control_assert(pwm->rst); >> >> + return ret; >> >> + } >> >> + >> >> + platform_set_drvdata(pdev, pwm); >> >> + >> >> + return 0; >> >> +} >> >> + >> >> +static int starfive_pwm_ptc_remove(struct platform_device *dev) >> >> +{ >> >> + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); >> >> + >> >> + reset_control_assert(pwm->rst); >> >> + clk_disable_unprepare(pwm->clk); >> >> + >> >> + return 0; >> >> +} >> >> + >> >> +static const struct of_device_id starfive_pwm_ptc_of_match[] = { >> >> + { .compatible = "starfive,jh7100-pwm" }, >> >> + { .compatible = "starfive,jh7110-pwm" }, >> >> + { /* sentinel */ } >> >> +}; >> >> +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); >> >> + >> >> +static struct platform_driver starfive_pwm_ptc_driver = { >> >> + .probe = starfive_pwm_ptc_probe, >> >> + .remove = starfive_pwm_ptc_remove, >> >> + .driver = { >> >> + .name = "pwm-starfive-ptc", >> > >> > Here >> > >> >> + .of_match_table = starfive_pwm_ptc_of_match, >> >> + }, >> >> +}; >> >> +module_platform_driver(starfive_pwm_ptc_driver); >> >> + >> >> +MODULE_AUTHOR("Jieqin Chen"); >> >> +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); >> >> +MODULE_DESCRIPTION("StarFive PWM PTC driver"); >> > >> > ..and here you're also still calling the driver PTC without explaining why. >> > >> >> +MODULE_LICENSE("GPL"); >> >> -- >> >> 2.34.1 >> >>
Hello, On Mon, Sep 25, 2023 at 10:31:49AM +0000, Emil Renner Berthing wrote: > William Qiu wrote: > > The PTC, short for PWM/TIMER/CONUTER, comes from OpenCore's ip, but only PWM > > mode is used in the JH7110. So the register still has the word "PTC". > > s the best way to change all the prefix to STARFIVE? > > I see. Yeah, since you're only using the P from PTC the PTC name doesn't make a > lot of sense anymore. I'd just call this whole driver > STARFIVE_PWM_/starfive_pwm_ consistently. I don't care much how the driver is named iff there is only a single type of hardware unit on this platform that can be used as a PWM. However if the hardware manual calls this unit PTC I'd at least mention that in a comment at the top of the driver. Thanks Uwe
On Mon, Sep 25, 2023 at 06:27:16PM +0800, William Qiu wrote: > > > On 2023/9/23 20:08, Emil Renner Berthing wrote: > > William Qiu wrote: > >> Add Pulse Width Modulation driver support for StarFive > >> JH7100 and JH7110 SoC. > >> > >> Co-developed-by: Hal Feng <hal.feng@starfivetech.com> > >> Signed-off-by: Hal Feng <hal.feng@starfivetech.com> > >> Signed-off-by: William Qiu <william.qiu@starfivetech.com> > >> --- > >> MAINTAINERS | 7 ++ > >> drivers/pwm/Kconfig | 9 ++ > >> drivers/pwm/Makefile | 1 + > >> drivers/pwm/pwm-starfive.c | 190 +++++++++++++++++++++++++++++++++++++ > >> 4 files changed, 207 insertions(+) > >> create mode 100644 drivers/pwm/pwm-starfive.c > >> > >> diff --git a/MAINTAINERS b/MAINTAINERS > >> index bf0f54c24f81..bc2155bd2712 100644 > >> --- a/MAINTAINERS > >> +++ b/MAINTAINERS > >> @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* > >> F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h > >> F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h > >> > >> +STARFIVE JH71X0 PWM DRIVERS > >> +M: William Qiu <william.qiu@starfivetech.com> > >> +M: Hal Feng <hal.feng@starfivetech.com> > >> +S: Supported > >> +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml > >> +F: drivers/pwm/pwm-starfive-ptc.c > >> + > >> STARFIVE JH71X0 RESET CONTROLLER DRIVERS > >> M: Emil Renner Berthing <kernel@esmil.dk> > >> M: Hal Feng <hal.feng@starfivetech.com> > >> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig > >> index 8ebcddf91f7b..e2ee0169f6e4 100644 > >> --- a/drivers/pwm/Kconfig > >> +++ b/drivers/pwm/Kconfig > >> @@ -569,6 +569,15 @@ config PWM_SPRD > >> To compile this driver as a module, choose M here: the module > >> will be called pwm-sprd. > >> > >> +config PWM_STARFIVE > >> + tristate "StarFive PWM support" > >> + depends on ARCH_STARFIVE || COMPILE_TEST > >> + help > >> + Generic PWM framework driver for StarFive SoCs. > >> + > >> + To compile this driver as a module, choose M here: the module > >> + will be called pwm-starfive. > >> + > >> config PWM_STI > >> tristate "STiH4xx PWM support" > >> depends on ARCH_STI || COMPILE_TEST > >> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile > >> index c822389c2a24..93b954376873 100644 > >> --- a/drivers/pwm/Makefile > >> +++ b/drivers/pwm/Makefile > >> @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o > >> obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o > >> obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o > >> obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o > >> +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o > >> obj-$(CONFIG_PWM_STI) += pwm-sti.o > >> obj-$(CONFIG_PWM_STM32) += pwm-stm32.o > >> obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o > >> diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c > > > > Hi William, > > > > You never answered my questions about what PTC is short for and if there are > > other PWMs on the JH7110. You just removed -ptc from the name of this file.. > > > Hi Emil, > > The PTC, short for PWM/TIMER/CONUTER, comes from OpenCore's ip, but only PWM > mode is used in the JH7110. So the register still has the word "PTC". > s the best way to change all the prefix to STARFIVE? This is the first time I see mentioned that this is based on an Open- Cores IP. It's definitely something you want to note somewhere so that others can reuse this driver if they've incorporated the same IP into their device. Given the above it might be better to name this something different entirely. The original OpenCores PTC IP seems to be single-instance, but that's about the only difference here (i.e. the OpenCores IP lists one clock and one reset, which this driver supports). So it'd be easy to turn this into a generic OpenCores driver and then use the starfive compatible string(s) to parameterize (number of instances, register stride, etc.). Thierry
diff --git a/MAINTAINERS b/MAINTAINERS index bf0f54c24f81..bc2155bd2712 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -20495,6 +20495,13 @@ F: drivers/pinctrl/starfive/pinctrl-starfive-jh71* F: include/dt-bindings/pinctrl/pinctrl-starfive-jh7100.h F: include/dt-bindings/pinctrl/starfive,jh7110-pinctrl.h +STARFIVE JH71X0 PWM DRIVERS +M: William Qiu <william.qiu@starfivetech.com> +M: Hal Feng <hal.feng@starfivetech.com> +S: Supported +F: Documentation/devicetree/bindings/pwm/starfive,jh7100-pwm.yaml +F: drivers/pwm/pwm-starfive-ptc.c + STARFIVE JH71X0 RESET CONTROLLER DRIVERS M: Emil Renner Berthing <kernel@esmil.dk> M: Hal Feng <hal.feng@starfivetech.com> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 8ebcddf91f7b..e2ee0169f6e4 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -569,6 +569,15 @@ config PWM_SPRD To compile this driver as a module, choose M here: the module will be called pwm-sprd. +config PWM_STARFIVE + tristate "StarFive PWM support" + depends on ARCH_STARFIVE || COMPILE_TEST + help + Generic PWM framework driver for StarFive SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-starfive. + config PWM_STI tristate "STiH4xx PWM support" depends on ARCH_STI || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index c822389c2a24..93b954376873 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o +obj-$(CONFIG_PWM_STARFIVE) += pwm-starfive.o obj-$(CONFIG_PWM_STI) += pwm-sti.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o diff --git a/drivers/pwm/pwm-starfive.c b/drivers/pwm/pwm-starfive.c new file mode 100644 index 000000000000..d390349fc95d --- /dev/null +++ b/drivers/pwm/pwm-starfive.c @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * PWM driver for the StarFive JH71x0 SoC + * + * Copyright (C) 2018-2023 StarFive Technology Co., Ltd. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pwm.h> +#include <linux/reset.h> +#include <linux/slab.h> + +/* Access PTC register (CNTR, HRC, LRC and CTRL) */ +#define REG_PTC_BASE_ADDR_SUB(base, N) ((base) + (((N) > 3) ? \ + (((N) % 4) * 0x10 + (1 << 15)) : ((N) * 0x10))) +#define REG_PTC_RPTC_CNTR(base, N) (REG_PTC_BASE_ADDR_SUB(base, N)) +#define REG_PTC_RPTC_HRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x4) +#define REG_PTC_RPTC_LRC(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0x8) +#define REG_PTC_RPTC_CTRL(base, N) (REG_PTC_BASE_ADDR_SUB(base, N) + 0xC) + +/* PTC_RPTC_CTRL register bits*/ +#define PTC_EN BIT(0) +#define PTC_ECLK BIT(1) +#define PTC_NEC BIT(2) +#define PTC_OE BIT(3) +#define PTC_SIGNLE BIT(4) +#define PTC_INTE BIT(5) +#define PTC_INT BIT(6) +#define PTC_CNTRRST BIT(7) +#define PTC_CAPTE BIT(8) + +struct starfive_pwm_ptc_device { + struct pwm_chip chip; + struct clk *clk; + struct reset_control *rst; + void __iomem *regs; + u32 clk_rate; /* PWM APB clock frequency */ +}; + +static inline struct starfive_pwm_ptc_device * +chip_to_starfive_ptc(struct pwm_chip *chip) + +{ + return container_of(chip, struct starfive_pwm_ptc_device, chip); +} + +static int starfive_pwm_ptc_get_state(struct pwm_chip *chip, + struct pwm_device *dev, + struct pwm_state *state) +{ + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); + u32 period_data, duty_data, ctrl_data; + + period_data = readl(REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); + duty_data = readl(REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); + + state->period = DIV_ROUND_CLOSEST_ULL((u64)period_data * NSEC_PER_SEC, pwm->clk_rate); + state->duty_cycle = DIV_ROUND_CLOSEST_ULL((u64)duty_data * NSEC_PER_SEC, pwm->clk_rate); + state->polarity = PWM_POLARITY_INVERSED; + state->enabled = (ctrl_data & PTC_EN) ? true : false; + + return 0; +} + +static int starfive_pwm_ptc_apply(struct pwm_chip *chip, + struct pwm_device *dev, + const struct pwm_state *state) +{ + struct starfive_pwm_ptc_device *pwm = chip_to_starfive_ptc(chip); + u32 period_data, duty_data, ctrl_data = 0; + + if (state->polarity != PWM_POLARITY_INVERSED) + return -EINVAL; + + period_data = DIV_ROUND_CLOSEST_ULL(state->period * pwm->clk_rate, + NSEC_PER_SEC); + duty_data = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * pwm->clk_rate, + NSEC_PER_SEC); + + writel(period_data, REG_PTC_RPTC_LRC(pwm->regs, dev->hwpwm)); + writel(duty_data, REG_PTC_RPTC_HRC(pwm->regs, dev->hwpwm)); + writel(0, REG_PTC_RPTC_CNTR(pwm->regs, dev->hwpwm)); + + ctrl_data = readl(REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); + if (state->enabled) + writel(ctrl_data | PTC_EN | PTC_OE, REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); + else + writel(ctrl_data & ~(PTC_EN | PTC_OE), REG_PTC_RPTC_CTRL(pwm->regs, dev->hwpwm)); + + return 0; +} + +static const struct pwm_ops starfive_pwm_ptc_ops = { + .get_state = starfive_pwm_ptc_get_state, + .apply = starfive_pwm_ptc_apply, + .owner = THIS_MODULE, +}; + +static int starfive_pwm_ptc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct starfive_pwm_ptc_device *pwm; + struct pwm_chip *chip; + int ret; + + pwm = devm_kzalloc(dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) + return -ENOMEM; + + chip = &pwm->chip; + chip->dev = dev; + chip->ops = &starfive_pwm_ptc_ops; + chip->npwm = 8; + chip->of_pwm_n_cells = 3; + + pwm->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(pwm->regs)) + return dev_err_probe(dev, PTR_ERR(pwm->regs), + "Unable to map IO resources\n"); + + pwm->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(pwm->clk)) + return dev_err_probe(dev, PTR_ERR(pwm->clk), + "Unable to get pwm's clock\n"); + + pwm->rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(pwm->rst)) + return dev_err_probe(dev, PTR_ERR(pwm->rst), + "Unable to get pwm's reset\n"); + + ret = reset_control_deassert(pwm->rst); + if (ret) { + dev_err(dev, "Failed to enable clock for pwm: %d\n", ret); + return ret; + } + + pwm->clk_rate = clk_get_rate(pwm->clk); + if (pwm->clk_rate <= 0) { + dev_warn(dev, "Failed to get APB clock rate\n"); + return -EINVAL; + } + + ret = devm_pwmchip_add(dev, chip); + if (ret < 0) { + dev_err(dev, "Cannot register PTC: %d\n", ret); + clk_disable_unprepare(pwm->clk); + reset_control_assert(pwm->rst); + return ret; + } + + platform_set_drvdata(pdev, pwm); + + return 0; +} + +static int starfive_pwm_ptc_remove(struct platform_device *dev) +{ + struct starfive_pwm_ptc_device *pwm = platform_get_drvdata(dev); + + reset_control_assert(pwm->rst); + clk_disable_unprepare(pwm->clk); + + return 0; +} + +static const struct of_device_id starfive_pwm_ptc_of_match[] = { + { .compatible = "starfive,jh7100-pwm" }, + { .compatible = "starfive,jh7110-pwm" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, starfive_pwm_ptc_of_match); + +static struct platform_driver starfive_pwm_ptc_driver = { + .probe = starfive_pwm_ptc_probe, + .remove = starfive_pwm_ptc_remove, + .driver = { + .name = "pwm-starfive-ptc", + .of_match_table = starfive_pwm_ptc_of_match, + }, +}; +module_platform_driver(starfive_pwm_ptc_driver); + +MODULE_AUTHOR("Jieqin Chen"); +MODULE_AUTHOR("Hal Feng <hal.feng@starfivetech.com>"); +MODULE_DESCRIPTION("StarFive PWM PTC driver"); +MODULE_LICENSE("GPL");