devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC
@ 2023-10-05 13:05 Jisheng Zhang
  2023-10-05 13:05 ` [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller Jisheng Zhang
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Jisheng Zhang @ 2023-10-05 13:05 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Guo Ren, Fu Wei
  Cc: linux-pwm, devicetree, linux-kernel, linux-riscv

T-HEAD SoCs such as the TH1520 contain a PWM controller used to
control the LCD backlight, fan and so on. Add the PWM driver support
for it.

Since the clk part isn't mainlined, so SoC dts(i) changes are not
included in this series. However, it can be tested by using fixed-clock.

since v2:
 - collect Reviewed-by tag
 - add CTRL_ prefix for THEAD_PWM_CTRL register bit macros
 - use pm_runtime_resume_and_get() instead of pm_runtime_get_sync() and
   check its return value.
 - remove unnecessary casts
 - call pm_runtime_put_sync() when pwm channel is disabled
 - use devm_pm_runtime_enable() and then drop .remove()
 - properly consider if pwm is programmed by bootloader or other
   pre-linux env.
 - simplify thead_pwm_runtime_resume() code as Uwe suggested
 - bool ever_started -> u8 channel_ever_started since we have 6 channels
 - use 3 for #pwm-cells 

since v1:
 - update commit msg and yaml filename to address Conor's comment
 - use devm_clk_get_enabled() and devm_pwmchip_add()
 - implement .get_state()
 - properly handle overflow
 - introduce thead_pwm_from_chip() inline function
 - document Limitations
 - address pm_runtime_get/put pingpong comment


Jisheng Zhang (2):
  dt-bindings: pwm: Add T-HEAD PWM controller
  pwm: add T-HEAD PWM driver

 .../bindings/pwm/thead,th1520-pwm.yaml        |  44 +++
 drivers/pwm/Kconfig                           |  11 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-thead.c                       | 270 ++++++++++++++++++
 4 files changed, 326 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
 create mode 100644 drivers/pwm/pwm-thead.c

-- 
2.40.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller
  2023-10-05 13:05 [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
@ 2023-10-05 13:05 ` Jisheng Zhang
  2023-11-13 21:37   ` Uwe Kleine-König
  2023-10-05 13:05 ` [PATCH v3 2/2] pwm: add T-HEAD PWM driver Jisheng Zhang
  2023-11-06 14:49 ` [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
  2 siblings, 1 reply; 8+ messages in thread
From: Jisheng Zhang @ 2023-10-05 13:05 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Guo Ren, Fu Wei
  Cc: linux-pwm, devicetree, linux-kernel, linux-riscv, Rob Herring

T-HEAD SoCs such as the TH1520 contain a PWM controller used
to control the LCD backlight, fan and so on.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 .../bindings/pwm/thead,th1520-pwm.yaml        | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml

diff --git a/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
new file mode 100644
index 000000000000..e75d8e9f24c5
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
@@ -0,0 +1,44 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/thead,th1520-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: T-HEAD TH1520 PWM
+
+maintainers:
+  - Jisheng Zhang <jszhang@kernel.org>
+
+allOf:
+  - $ref: pwm.yaml#
+
+properties:
+  compatible:
+    enum:
+      - thead,th1520-pwm
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  "#pwm-cells":
+    const: 3
+
+required:
+  - compatible
+  - reg
+  - clocks
+
+additionalProperties: false
+
+examples:
+  - |
+
+    pwm@ec01c000 {
+        compatible = "thead,th1520-pwm";
+        reg = <0xec01c000 0x1000>;
+        clocks = <&clk 1>;
+        #pwm-cells = <3>;
+    };
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v3 2/2] pwm: add T-HEAD PWM driver
  2023-10-05 13:05 [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
  2023-10-05 13:05 ` [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller Jisheng Zhang
@ 2023-10-05 13:05 ` Jisheng Zhang
  2023-11-13 21:56   ` Uwe Kleine-König
  2024-04-15 11:48   ` Thomas Bonnefille
  2023-11-06 14:49 ` [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
  2 siblings, 2 replies; 8+ messages in thread
From: Jisheng Zhang @ 2023-10-05 13:05 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Guo Ren, Fu Wei
  Cc: linux-pwm, devicetree, linux-kernel, linux-riscv

T-HEAD SoCs such as the TH1520 contain a PWM controller used
to control the LCD backlight, fan and so on. Add driver for it.

Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
 drivers/pwm/Kconfig     |  11 ++
 drivers/pwm/Makefile    |   1 +
 drivers/pwm/pwm-thead.c | 270 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 282 insertions(+)
 create mode 100644 drivers/pwm/pwm-thead.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 8ebcddf91f7b..428fa365a19a 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -637,6 +637,17 @@ config PWM_TEGRA
 	  To compile this driver as a module, choose M here: the module
 	  will be called pwm-tegra.
 
+config PWM_THEAD
+	tristate "T-HEAD PWM support"
+	depends on ARCH_THEAD || COMPILE_TEST
+	depends on HAS_IOMEM
+	help
+	  Generic PWM framework driver for the PWFM controller found on THEAD
+	  SoCs.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-thead.
+
 config PWM_TIECAP
 	tristate "ECAP PWM support"
 	depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index c822389c2a24..4c317e6316e8 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_PWM_STMPE)		+= pwm-stmpe.o
 obj-$(CONFIG_PWM_SUN4I)		+= pwm-sun4i.o
 obj-$(CONFIG_PWM_SUNPLUS)	+= pwm-sunplus.o
 obj-$(CONFIG_PWM_TEGRA)		+= pwm-tegra.o
+obj-$(CONFIG_PWM_THEAD)		+= pwm-thead.o
 obj-$(CONFIG_PWM_TIECAP)	+= pwm-tiecap.o
 obj-$(CONFIG_PWM_TIEHRPWM)	+= pwm-tiehrpwm.o
 obj-$(CONFIG_PWM_TWL)		+= pwm-twl.o
diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c
new file mode 100644
index 000000000000..3b9ffddfe33d
--- /dev/null
+++ b/drivers/pwm/pwm-thead.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * T-HEAD PWM driver
+ *
+ * Copyright (C) 2021 Alibaba Group Holding Limited.
+ * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
+ *
+ * Limitations:
+ * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used
+ *   to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle
+ *   is used to "disable" the channel.
+ * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is
+ *   started.
+ * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty.
+ * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1
+ *   step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it
+ *   to 0 beforehand.
+ * - Polarity can only be changed if never started before.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define THEAD_PWM_MAX_NUM		6
+#define THEAD_PWM_MAX_PERIOD		GENMASK(31, 0)
+#define THEAD_PWM_MAX_DUTY		GENMASK(31, 0)
+
+#define THEAD_PWM_CHN_BASE(n)		((n) * 0x20)
+#define THEAD_PWM_CTRL(n)		(THEAD_PWM_CHN_BASE(n) + 0x00)
+#define  THEAD_PWM_CTRL_START		BIT(0)
+#define  THEAD_PWM_CTRL_SOFT_RST		BIT(1)
+#define  THEAD_PWM_CTRL_CFG_UPDATE	BIT(2)
+#define  THEAD_PWM_CTRL_INTEN		BIT(3)
+#define  THEAD_PWM_CTRL_MODE		GENMASK(5, 4)
+#define  THEAD_PWM_CTRL_MODE_CONTINUOUS	FIELD_PREP(THEAD_PWM_CTRL_MODE, 2)
+#define  THEAD_PWM_CTRL_EVTRIG		GENMASK(7, 6)
+#define  THEAD_PWM_CTRL_FPOUT		BIT(8)
+#define  THEAD_PWM_CTRL_INFACTOUT	BIT(9)
+#define THEAD_PWM_RPT(n)		(THEAD_PWM_CHN_BASE(n) + 0x04)
+#define THEAD_PWM_PER(n)		(THEAD_PWM_CHN_BASE(n) + 0x08)
+#define THEAD_PWM_FP(n)			(THEAD_PWM_CHN_BASE(n) + 0x0c)
+#define THEAD_PWM_STATUS(n)		(THEAD_PWM_CHN_BASE(n) + 0x10)
+#define  THEAD_PWM_STATUS_CYCLE		GENMASK(7, 0)
+
+struct thead_pwm_chip {
+	struct pwm_chip chip;
+	void __iomem *mmio_base;
+	struct clk *clk;
+	u8 channel_ever_started;
+};
+
+static inline struct thead_pwm_chip *thead_pwm_from_chip(struct pwm_chip *chip)
+{
+	return container_of(chip, struct thead_pwm_chip, chip);
+}
+
+static int thead_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+			   const struct pwm_state *state)
+{
+	struct thead_pwm_chip *priv = thead_pwm_from_chip(chip);
+	u32 val = THEAD_PWM_CTRL_INFACTOUT | THEAD_PWM_CTRL_FPOUT | THEAD_PWM_CTRL_MODE_CONTINUOUS;
+	u64 period_cycle, duty_cycle, rate;
+	int ret;
+
+	/* if ever started, can't change the polarity */
+	if ((priv->channel_ever_started & (1 << pwm->hwpwm)) &&
+	    state->polarity != pwm->state.polarity)
+		return -EINVAL;
+
+	if (!state->enabled) {
+		if (pwm->state.enabled) {
+			val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+			val &= ~THEAD_PWM_CTRL_CFG_UPDATE;
+			writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+
+			writel(0, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
+
+			val |= THEAD_PWM_CTRL_CFG_UPDATE;
+			writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+			pm_runtime_put_sync(chip->dev);
+		}
+		return 0;
+	}
+
+	if (!pwm->state.enabled) {
+		ret = pm_runtime_resume_and_get(chip->dev);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (state->polarity == PWM_POLARITY_INVERSED)
+		val &= ~THEAD_PWM_CTRL_FPOUT;
+
+	writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+
+	rate = clk_get_rate(priv->clk);
+	/*
+	 * The following calculations might overflow if clk is bigger
+	 * than 1 GHz. In practise it's 24MHz, so this limitation
+	 * is only theoretic.
+	 */
+	if (rate > NSEC_PER_SEC)
+		return -EINVAL;
+
+	period_cycle = mul_u64_u64_div_u64(rate, state->period, NSEC_PER_SEC);
+	if (period_cycle > THEAD_PWM_MAX_PERIOD)
+		period_cycle = THEAD_PWM_MAX_PERIOD;
+	/*
+	 * With limitation above we have period_cycle <= THEAD_PWM_MAX_PERIOD,
+	 * so this cannot overflow.
+	 */
+	writel(period_cycle, priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm));
+
+	duty_cycle = mul_u64_u64_div_u64(rate, state->duty_cycle, NSEC_PER_SEC);
+	if (duty_cycle > THEAD_PWM_MAX_DUTY)
+		duty_cycle = THEAD_PWM_MAX_DUTY;
+	/*
+	 * With limitation above we have duty_cycle <= THEAD_PWM_MAX_DUTY,
+	 * so this cannot overflow.
+	 */
+	writel(duty_cycle, priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
+
+	val |= THEAD_PWM_CTRL_CFG_UPDATE;
+	writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+
+	if (!pwm->state.enabled) {
+		val |= THEAD_PWM_CTRL_START;
+		writel(val, priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+		priv->channel_ever_started |= 1 << pwm->hwpwm;
+	}
+
+	return 0;
+}
+
+static int thead_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
+			       struct pwm_state *state)
+{
+	struct thead_pwm_chip *priv = thead_pwm_from_chip(chip);
+	u64 rate = clk_get_rate(priv->clk);
+	u32 val;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(chip->dev);
+	if (ret < 0)
+		return ret;
+
+	val = readl(priv->mmio_base + THEAD_PWM_CTRL(pwm->hwpwm));
+	if (val & THEAD_PWM_CTRL_FPOUT)
+		state->polarity = PWM_POLARITY_NORMAL;
+	else
+		state->polarity = PWM_POLARITY_INVERSED;
+
+	val = readl(priv->mmio_base + THEAD_PWM_PER(pwm->hwpwm));
+	/*
+	 * val 32 bits, multiply NSEC_PER_SEC, won't overflow.
+	 */
+	state->period = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate);
+
+	val = readl(priv->mmio_base + THEAD_PWM_FP(pwm->hwpwm));
+	state->enabled = !!val;
+	/*
+	 * val 32 bits, multiply NSEC_PER_SEC, won't overflow.
+	 */
+	state->duty_cycle = DIV64_U64_ROUND_UP((u64)val * NSEC_PER_SEC, rate);
+
+	pm_runtime_put_sync(chip->dev);
+
+	return 0;
+}
+
+static const struct pwm_ops thead_pwm_ops = {
+	.apply = thead_pwm_apply,
+	.get_state = thead_pwm_get_state,
+	.owner = THIS_MODULE,
+};
+
+static int __maybe_unused thead_pwm_runtime_suspend(struct device *dev)
+{
+	struct thead_pwm_chip *priv = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(priv->clk);
+
+	return 0;
+}
+
+static int __maybe_unused thead_pwm_runtime_resume(struct device *dev)
+{
+	struct thead_pwm_chip *priv = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(priv->clk);
+	if (ret)
+		dev_err(dev, "failed to enable pwm clock(%pe)\n", ERR_PTR(ret));
+
+	return ret;
+}
+
+static int thead_pwm_probe(struct platform_device *pdev)
+{
+	struct thead_pwm_chip *priv;
+	int ret, i;
+	u32 val;
+
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	platform_set_drvdata(pdev, priv);
+
+	priv->mmio_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->mmio_base))
+		return PTR_ERR(priv->mmio_base);
+
+	priv->clk = devm_clk_get_enabled(&pdev->dev, NULL);
+	if (IS_ERR(priv->clk))
+		return PTR_ERR(priv->clk);
+
+	priv->chip.ops = &thead_pwm_ops;
+	priv->chip.dev = &pdev->dev;
+	priv->chip.npwm = THEAD_PWM_MAX_NUM;
+
+	/* check whether PWM is ever started or not */
+	for (i = 0; i < priv->chip.npwm; i++) {
+		val = readl(priv->mmio_base + THEAD_PWM_FP(i));
+		if (val)
+			priv->channel_ever_started |= 1 << i;
+	}
+
+	ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
+	if (ret)
+		return ret;
+
+	devm_pm_runtime_enable(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id thead_pwm_dt_ids[] = {
+	{.compatible = "thead,th1520-pwm",},
+	{/* sentinel */}
+};
+MODULE_DEVICE_TABLE(of, thead_pwm_dt_ids);
+
+static const struct dev_pm_ops thead_pwm_pm_ops = {
+	SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL)
+};
+
+static struct platform_driver thead_pwm_driver = {
+	.driver = {
+		.name = "thead-pwm",
+		.of_match_table = thead_pwm_dt_ids,
+		.pm = &thead_pwm_pm_ops,
+	},
+	.probe = thead_pwm_probe,
+};
+module_platform_driver(thead_pwm_driver);
+
+MODULE_AUTHOR("Wei Liu <lw312886@linux.alibaba.com>");
+MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>");
+MODULE_DESCRIPTION("T-HEAD pwm driver");
+MODULE_LICENSE("GPL v2");
-- 
2.40.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC
  2023-10-05 13:05 [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
  2023-10-05 13:05 ` [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller Jisheng Zhang
  2023-10-05 13:05 ` [PATCH v3 2/2] pwm: add T-HEAD PWM driver Jisheng Zhang
@ 2023-11-06 14:49 ` Jisheng Zhang
  2023-11-06 15:43   ` Uwe Kleine-König
  2 siblings, 1 reply; 8+ messages in thread
From: Jisheng Zhang @ 2023-11-06 14:49 UTC (permalink / raw)
  To: Thierry Reding, Uwe Kleine-König, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Guo Ren, Fu Wei
  Cc: linux-pwm, devicetree, linux-kernel, linux-riscv

On Thu, Oct 05, 2023 at 09:05:17PM +0800, Jisheng Zhang wrote:
> T-HEAD SoCs such as the TH1520 contain a PWM controller used to
> control the LCD backlight, fan and so on. Add the PWM driver support
> for it.
> 
> Since the clk part isn't mainlined, so SoC dts(i) changes are not
> included in this series. However, it can be tested by using fixed-clock.
> 
> since v2:
>  - collect Reviewed-by tag
>  - add CTRL_ prefix for THEAD_PWM_CTRL register bit macros
>  - use pm_runtime_resume_and_get() instead of pm_runtime_get_sync() and
>    check its return value.
>  - remove unnecessary casts
>  - call pm_runtime_put_sync() when pwm channel is disabled
>  - use devm_pm_runtime_enable() and then drop .remove()
>  - properly consider if pwm is programmed by bootloader or other
>    pre-linux env.
>  - simplify thead_pwm_runtime_resume() code as Uwe suggested
>  - bool ever_started -> u8 channel_ever_started since we have 6 channels
>  - use 3 for #pwm-cells 
> 
> since v1:
>  - update commit msg and yaml filename to address Conor's comment
>  - use devm_clk_get_enabled() and devm_pwmchip_add()
>  - implement .get_state()
>  - properly handle overflow
>  - introduce thead_pwm_from_chip() inline function
>  - document Limitations
>  - address pm_runtime_get/put pingpong comment
> 
> 
> Jisheng Zhang (2):
>   dt-bindings: pwm: Add T-HEAD PWM controller
>   pwm: add T-HEAD PWM driver

Hi Thierry, Uwe,

Kind ping, is there any chance for this series to be merged for v6.7?

Thanks
> 
>  .../bindings/pwm/thead,th1520-pwm.yaml        |  44 +++
>  drivers/pwm/Kconfig                           |  11 +
>  drivers/pwm/Makefile                          |   1 +
>  drivers/pwm/pwm-thead.c                       | 270 ++++++++++++++++++
>  4 files changed, 326 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pwm/thead,th1520-pwm.yaml
>  create mode 100644 drivers/pwm/pwm-thead.c
> 
> -- 
> 2.40.1
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC
  2023-11-06 14:49 ` [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
@ 2023-11-06 15:43   ` Uwe Kleine-König
  0 siblings, 0 replies; 8+ messages in thread
From: Uwe Kleine-König @ 2023-11-06 15:43 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Thierry Reding, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Guo Ren, Fu Wei, linux-pwm, devicetree, linux-kernel, linux-riscv

[-- Attachment #1: Type: text/plain, Size: 702 bytes --]

Hi,

On Mon, Nov 06, 2023 at 10:49:33PM +0800, Jisheng Zhang wrote:
> Kind ping, is there any chance for this series to be merged for v6.7?

I didn't forget about reviewing your driver, but as such a review takes
quite some time I often fail to do the review in a timely manner. Sorry
about that.

Having said that I guess Thierry's tree won't pick up any new patches
given that we already crossed the middle of the merge window and patches
are supposed to be in next for some time before being sent to Linus.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller
  2023-10-05 13:05 ` [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller Jisheng Zhang
@ 2023-11-13 21:37   ` Uwe Kleine-König
  0 siblings, 0 replies; 8+ messages in thread
From: Uwe Kleine-König @ 2023-11-13 21:37 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Thierry Reding, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Guo Ren, Fu Wei, linux-pwm, devicetree, linux-kernel, linux-riscv,
	Rob Herring

[-- Attachment #1: Type: text/plain, Size: 522 bytes --]

On Thu, Oct 05, 2023 at 09:05:18PM +0800, Jisheng Zhang wrote:
> T-HEAD SoCs such as the TH1520 contain a PWM controller used
> to control the LCD backlight, fan and so on.
> 
> Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
> Reviewed-by: Rob Herring <robh@kernel.org>

Acked-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 2/2] pwm: add T-HEAD PWM driver
  2023-10-05 13:05 ` [PATCH v3 2/2] pwm: add T-HEAD PWM driver Jisheng Zhang
@ 2023-11-13 21:56   ` Uwe Kleine-König
  2024-04-15 11:48   ` Thomas Bonnefille
  1 sibling, 0 replies; 8+ messages in thread
From: Uwe Kleine-König @ 2023-11-13 21:56 UTC (permalink / raw)
  To: Jisheng Zhang
  Cc: Thierry Reding, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Guo Ren, Fu Wei, linux-pwm, devicetree, linux-kernel, linux-riscv

[-- Attachment #1: Type: text/plain, Size: 2119 bytes --]

Hello,

On Thu, Oct 05, 2023 at 09:05:19PM +0800, Jisheng Zhang wrote:
> diff --git a/drivers/pwm/pwm-thead.c b/drivers/pwm/pwm-thead.c
> new file mode 100644
> index 000000000000..3b9ffddfe33d
> --- /dev/null
> +++ b/drivers/pwm/pwm-thead.c
> @@ -0,0 +1,270 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * T-HEAD PWM driver
> + *
> + * Copyright (C) 2021 Alibaba Group Holding Limited.
> + * Copyright (C) 2023 Jisheng Zhang <jszhang@kernel.org>
> + *
> + * Limitations:
> + * - The THEAD_PWM_CTRL_START bit is only effective when 0 -> 1, which is used
> + *   to start the channel, 1 -> 0 doesn't change anything. so 0 % duty cycle
> + *   is used to "disable" the channel.
> + * - The THEAD_PWM_CTRL_START bit is automatically cleared once PWM channel is
> + *   started.
> + * - The THEAD_PWM_CFG_UPDATE atomically updates and only updates period and duty.
> + * - To update period and duty, THEAD_PWM_CFG_UPDATE needs to go through 0 -> 1
> + *   step, I.E if THEAD_PWM_CFG_UPDATE is already 1, it's necessary to clear it
> + *   to 0 beforehand.
> + * - Polarity can only be changed if never started before.

Questions I'd like to have answered here additionally are:

 - How does the hardware behave when it's disabled? Typical canditates
   are:
    - drives the inactive level
    - freezes where it just happens to be when disable gets effective
    - disable drivers (HIGH-Z)
    - drives low

 - Does the hardware complete the current running period when apply is
   called with enabled=false?

 - Does the hardware complete the current running period when apply is
   called with enabled=true?

> +static const struct dev_pm_ops thead_pwm_pm_ops = {
> +	SET_RUNTIME_PM_OPS(thead_pwm_runtime_suspend, thead_pwm_runtime_resume, NULL)
> +};

Please see
https://lore.kernel.org/linux-pwm/20231023174616.2282067-13-u.kleine-koenig@pengutronix.de/t/
how this can be improved.

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | https://www.pengutronix.de/ |

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v3 2/2] pwm: add T-HEAD PWM driver
  2023-10-05 13:05 ` [PATCH v3 2/2] pwm: add T-HEAD PWM driver Jisheng Zhang
  2023-11-13 21:56   ` Uwe Kleine-König
@ 2024-04-15 11:48   ` Thomas Bonnefille
  1 sibling, 0 replies; 8+ messages in thread
From: Thomas Bonnefille @ 2024-04-15 11:48 UTC (permalink / raw)
  To: jszhang
  Cc: conor+dt, devicetree, guoren, krzysztof.kozlowski+dt,
	linux-kernel, linux-pwm, linux-riscv, robh+dt, thierry.reding,
	u.kleine-koenig, wefu, Miquel Raynal, Thomas Petazzoni

 > T-HEAD SoCs such as the TH1520 contain a PWM controller used
 > to control the LCD backlight, fan and so on. Add driver for it.
 >
 > Signed-off-by: Jisheng Zhang <jszhang@kernel.org > ---

Hello,
I've just tested your driver and it works flawlessly on the 
BeagleV-Ahead with the last mainline kernel. However, I had to modify 
some portion of the code to comply with the last kernel needs.

 > +static const struct pwm_ops thead_pwm_ops = {
 > +    .apply = thead_pwm_apply,
 > +    .get_state = thead_pwm_get_state,
 > +    .owner = THIS_MODULE,

Since commit 384461abcab6, the owner of a pwm_ops structure is implicit 
and so, you can (must) remove this last line now.

 > +};
 > ...
 > +static int thead_pwm_probe(struct platform_device *pdev)
 > +{
 > +    struct thead_pwm_chip *priv;
 > +    int ret, i;
 > +    u32 val;
 > +
 > +    priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
 > +    if (!priv)
 > +        return -ENOMEM;
 > +
 > +    platform_set_drvdata(pdev, priv);
 > +
 > +    priv->mmio_base = devm_platform_ioremap_resource(pdev, 0);
 > +    if (IS_ERR(priv->mmio_base))
 > +        return PTR_ERR(priv->mmio_base);
 > +
 > +    priv->clk = devm_clk_get_enabled(&pdev->dev, NULL);
 > +    if (IS_ERR(priv->clk))
 > +        return PTR_ERR(priv->clk);
 > +
 > +    priv->chip.ops = &thead_pwm_ops;
 > +    priv->chip.dev = &pdev->dev;
 > +    priv->chip.npwm = THEAD_PWM_MAX_NUM;
 > +
 > +    /* check whether PWM is ever started or not */
 > +    for (i = 0; i < priv->chip.npwm; i++) {
 > +        val = readl(priv->mmio_base + THEAD_PWM_FP(i));
 > +        if (val)
 > +            priv->channel_ever_started |= 1 << i;

					     BIT(i) ?
If the bootloader starts a PWM channel for some reason, it will not be 
referenced by the PM usage counter, I added this line in the if 
statement to counter this problem :
		pm_runtime_get(&pdev->dev);

 > +    }
 > +
 > +    ret = devm_pwmchip_add(&pdev->dev, &priv->chip);
 > +    if (ret)
 > +        return ret;
 > +
 > +    devm_pm_runtime_enable(&pdev->dev);
 > +
 > +    return 0;
 > +}


Thank you for your work. With the above comments addressed:

Tested-by: Thomas Bonnefille <thomas.bonnefille@bootlin.com>

Do you plan to send out a new iteration of this patch soon ?

Best regards,
Thomas Bonnefille

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-04-15 11:48 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-05 13:05 [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
2023-10-05 13:05 ` [PATCH v3 1/2] dt-bindings: pwm: Add T-HEAD PWM controller Jisheng Zhang
2023-11-13 21:37   ` Uwe Kleine-König
2023-10-05 13:05 ` [PATCH v3 2/2] pwm: add T-HEAD PWM driver Jisheng Zhang
2023-11-13 21:56   ` Uwe Kleine-König
2024-04-15 11:48   ` Thomas Bonnefille
2023-11-06 14:49 ` [PATCH v3 0/2] pwm: add driver for T-THEAD TH1520 SoC Jisheng Zhang
2023-11-06 15:43   ` Uwe Kleine-König

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).