2022-08-16 21:55:02

by Ben Dooks

[permalink] [raw]
Subject: [RFC v4 00/10] RFC on synpsys pwm driver changes

New version of the pwm timers patch, hopefully all review comments
are sorted out, however I have not had time to fully test this and
I do not have a PCI system to test it on either.

The series has been moved around a bit to try to get some of the
simpler changes in before splitting and to make the OF driver a
single addition.

v4:
- split pci and of into new modules
- fixup review comments
- fix typos in dt-bindings
v3:
- change the compatible name
- squash down pwm count patch
- fixup patch naming

v2:
- fix #pwm-cells count to be 3
- fix indetation
- merge the two clock patches
- add HAS_IOMEM as a config dependency


Ben Dooks (10):
dt-bindings: pwm: Document Synopsys DesignWare
snps,pwm-dw-apb-timers-pwm2
pwm: dwc: allow driver to be built with COMPILE_TEST
pwm: dwc: change &pci->dev to dev in probe
pwm: dwc: move memory alloc to own function
pwm: dwc: use devm_pwmchip_add
pwm: dwc: split pci out of core driver
pwm: dwc: make timer clock configurable
pwm: dwc: add of/platform support
pwm: dwc: add snps,pwm-number to limit pwm count
pwm: dwc: add PWM bit unset in get_state call

.../bindings/pwm/snps,dw-apb-timers-pwm2.yaml | 69 ++++++
drivers/pwm/Kconfig | 24 ++-
drivers/pwm/Makefile | 2 +
drivers/pwm/pwm-dwc-of.c | 86 ++++++++
drivers/pwm/pwm-dwc-pci.c | 134 ++++++++++++
drivers/pwm/pwm-dwc.c | 197 +++---------------
drivers/pwm/pwm-dwc.h | 60 ++++++
7 files changed, 402 insertions(+), 170 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pwm/snps,dw-apb-timers-pwm2.yaml
create mode 100644 drivers/pwm/pwm-dwc-of.c
create mode 100644 drivers/pwm/pwm-dwc-pci.c
create mode 100644 drivers/pwm/pwm-dwc.h

--
2.35.1


2022-08-16 22:01:51

by Ben Dooks

[permalink] [raw]
Subject: [RFC v4 06/10] pwm: dwc: split pci out of core driver

Moving towards adding non-pci support for the driver, move the pci
parts out of the core into their own module. This is partly due to
the module_driver() code only being allowed once in a module and also
to avoid a number of #ifdef if we build a single file in a system
without pci support.

Signed-off-by: Ben Dooks <[email protected]>
---
drivers/pwm/Kconfig | 14 +++-
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-dwc-pci.c | 133 ++++++++++++++++++++++++++++++++
drivers/pwm/pwm-dwc.c | 158 +-------------------------------------
drivers/pwm/pwm-dwc.h | 58 ++++++++++++++
5 files changed, 207 insertions(+), 157 deletions(-)
create mode 100644 drivers/pwm/pwm-dwc-pci.c
create mode 100644 drivers/pwm/pwm-dwc.h

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 3f3c53af4a56..a9f1c554db2b 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -175,15 +175,23 @@ config PWM_CROS_EC
Controller.

config PWM_DWC
- tristate "DesignWare PWM Controller"
- depends on PCI || COMPILE_TEST
+ tristate "DesignWare PWM Controller core"
depends on HAS_IOMEM
help
- PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
+ PWM driver for Synopsys DWC PWM Controller.

To compile this driver as a module, choose M here: the module
will be called pwm-dwc.

+config PWM_DWC_PCI
+ tristate "DesignWare PWM Controller core"
+ depends on PWM_DWC && HAS_IOMEM && PCI
+ help
+ PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-dwc-pci.
+
config PWM_EP93XX
tristate "Cirrus Logic EP93xx PWM support"
depends on ARCH_EP93XX || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 7bf1a29f02b8..a70d36623129 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
obj-$(CONFIG_PWM_CRC) += pwm-crc.o
obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
+obj-$(CONFIG_PWM_DWC_PCI) += pwm-dwc-pci.o
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o
diff --git a/drivers/pwm/pwm-dwc-pci.c b/drivers/pwm/pwm-dwc-pci.c
new file mode 100644
index 000000000000..2213d0e7f3c8
--- /dev/null
+++ b/drivers/pwm/pwm-dwc-pci.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DesignWare PWM Controller driver (PCI part)
+ *
+ * Copyright (C) 2018-2020 Intel Corporation
+ *
+ * Author: Felipe Balbi (Intel)
+ * Author: Jarkko Nikula <[email protected]>
+ * Author: Raymond Tan <[email protected]>
+ *
+ * Limitations:
+ * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low
+ * periods are one or more input clock periods long.
+ */
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+
+#include "pwm-dwc.h"
+
+static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
+{
+ struct device *dev = &pci->dev;
+ struct dwc_pwm *dwc;
+ int ret;
+
+ dwc = dwc_pwm_alloc(dev);
+ if (!dwc)
+ return -ENOMEM;
+
+ ret = pcim_enable_device(pci);
+ if (ret) {
+ dev_err(dev, "Failed to enable device (%pe)\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ pci_set_master(pci);
+
+ ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
+ if (ret) {
+ dev_err(dev, "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
+ return ret;
+ }
+
+ dwc->base = pcim_iomap_table(pci)[0];
+ if (!dwc->base) {
+ dev_err(dev, "Base address missing\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_pwmchip_add(dev, &dwc->chip);
+ if (ret)
+ return ret;
+
+ pm_runtime_put(dev);
+ pm_runtime_allow(dev);
+
+ return 0;
+}
+
+static void dwc_pwm_remove(struct pci_dev *pci)
+{
+ pm_runtime_forbid(&pci->dev);
+ pm_runtime_get_noresume(&pci->dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dwc_pwm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dwc_pwm *dwc = pci_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
+ if (dwc->chip.pwms[i].state.enabled) {
+ dev_err(dev, "PWM %u in use by consumer (%s)\n",
+ i, dwc->chip.pwms[i].label);
+ return -EBUSY;
+ }
+ dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i));
+ dwc->ctx[i].cnt2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(i));
+ dwc->ctx[i].ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(i));
+ }
+
+ return 0;
+}
+
+static int dwc_pwm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct dwc_pwm *dwc = pci_get_drvdata(pdev);
+ int i;
+
+ for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
+ dwc_pwm_writel(dwc, dwc->ctx[i].cnt, DWC_TIM_LD_CNT(i));
+ dwc_pwm_writel(dwc, dwc->ctx[i].cnt2, DWC_TIM_LD_CNT2(i));
+ dwc_pwm_writel(dwc, dwc->ctx[i].ctrl, DWC_TIM_CTRL(i));
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
+
+static const struct pci_device_id dwc_pwm_id_table[] = {
+ { PCI_VDEVICE(INTEL, 0x4bb7) }, /* Elkhart Lake */
+ { } /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc_pwm_id_table);
+
+static struct pci_driver dwc_pwm_driver = {
+ .name = "pwm-dwc",
+ .probe = dwc_pwm_probe,
+ .remove = dwc_pwm_remove,
+ .id_table = dwc_pwm_id_table,
+ .driver = {
+ .pm = &dwc_pwm_pm_ops,
+ },
+};
+
+module_pci_driver(dwc_pwm_driver);
+
+MODULE_AUTHOR("Felipe Balbi (Intel)");
+MODULE_AUTHOR("Jarkko Nikula <[email protected]>");
+MODULE_AUTHOR("Raymond Tan <[email protected]>");
+MODULE_DESCRIPTION("DesignWare PWM Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-dwc.c b/drivers/pwm/pwm-dwc.c
index 56cde9da2c0e..90a8ae1252a1 100644
--- a/drivers/pwm/pwm-dwc.c
+++ b/drivers/pwm/pwm-dwc.c
@@ -1,16 +1,12 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * DesignWare PWM Controller driver
+ * DesignWare PWM Controller driver core
*
* Copyright (C) 2018-2020 Intel Corporation
*
* Author: Felipe Balbi (Intel)
* Author: Jarkko Nikula <[email protected]>
* Author: Raymond Tan <[email protected]>
- *
- * Limitations:
- * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low
- * periods are one or more input clock periods long.
*/

#include <linux/bitops.h>
@@ -21,51 +17,7 @@
#include <linux/pm_runtime.h>
#include <linux/pwm.h>

-#define DWC_TIM_LD_CNT(n) ((n) * 0x14)
-#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0)
-#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04)
-#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08)
-#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c)
-#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10)
-
-#define DWC_TIMERS_INT_STS 0xa0
-#define DWC_TIMERS_EOI 0xa4
-#define DWC_TIMERS_RAW_INT_STS 0xa8
-#define DWC_TIMERS_COMP_VERSION 0xac
-
-#define DWC_TIMERS_TOTAL 8
-#define DWC_CLK_PERIOD_NS 10
-
-/* Timer Control Register */
-#define DWC_TIM_CTRL_EN BIT(0)
-#define DWC_TIM_CTRL_MODE BIT(1)
-#define DWC_TIM_CTRL_MODE_FREE (0 << 1)
-#define DWC_TIM_CTRL_MODE_USER (1 << 1)
-#define DWC_TIM_CTRL_INT_MASK BIT(2)
-#define DWC_TIM_CTRL_PWM BIT(3)
-
-struct dwc_pwm_ctx {
- u32 cnt;
- u32 cnt2;
- u32 ctrl;
-};
-
-struct dwc_pwm {
- struct pwm_chip chip;
- void __iomem *base;
- struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
-};
-#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip))
-
-static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
-{
- return readl(dwc->base + offset);
-}
-
-static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset)
-{
- writel(value, dwc->base + offset);
-}
+#include "pwm-dwc.h"

static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled)
{
@@ -196,7 +148,7 @@ static const struct pwm_ops dwc_pwm_ops = {
.owner = THIS_MODULE,
};

-static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
+struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
{
struct dwc_pwm *dwc;

@@ -211,109 +163,7 @@ static struct dwc_pwm *dwc_pwm_alloc(struct device *dev)
dev_set_drvdata(dev, dwc);
return dwc;
}
-
-static int dwc_pwm_probe(struct pci_dev *pci, const struct pci_device_id *id)
-{
- struct device *dev = &pci->dev;
- struct dwc_pwm *dwc;
- int ret;
-
- dwc = dwc_pwm_alloc(dev);
- if (!dwc)
- return -ENOMEM;
-
- ret = pcim_enable_device(pci);
- if (ret) {
- dev_err(dev, "Failed to enable device (%pe)\n", ERR_PTR(ret));
- return ret;
- }
-
- pci_set_master(pci);
-
- ret = pcim_iomap_regions(pci, BIT(0), pci_name(pci));
- if (ret) {
- dev_err(dev, "Failed to iomap PCI BAR (%pe)\n", ERR_PTR(ret));
- return ret;
- }
-
- dwc->base = pcim_iomap_table(pci)[0];
- if (!dwc->base) {
- dev_err(dev, "Base address missing\n");
- return -ENOMEM;
- }
-
- ret = devm_pwmchip_add(dev, &dwc->chip);
- if (ret)
- return ret;
-
- pm_runtime_put(dev);
- pm_runtime_allow(dev);
-
- return 0;
-}
-
-static void dwc_pwm_remove(struct pci_dev *pci)
-{
- pm_runtime_forbid(&pci->dev);
- pm_runtime_get_noresume(&pci->dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int dwc_pwm_suspend(struct device *dev)
-{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct dwc_pwm *dwc = pci_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
- if (dwc->chip.pwms[i].state.enabled) {
- dev_err(dev, "PWM %u in use by consumer (%s)\n",
- i, dwc->chip.pwms[i].label);
- return -EBUSY;
- }
- dwc->ctx[i].cnt = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(i));
- dwc->ctx[i].cnt2 = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(i));
- dwc->ctx[i].ctrl = dwc_pwm_readl(dwc, DWC_TIM_CTRL(i));
- }
-
- return 0;
-}
-
-static int dwc_pwm_resume(struct device *dev)
-{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
- struct dwc_pwm *dwc = pci_get_drvdata(pdev);
- int i;
-
- for (i = 0; i < DWC_TIMERS_TOTAL; i++) {
- dwc_pwm_writel(dwc, dwc->ctx[i].cnt, DWC_TIM_LD_CNT(i));
- dwc_pwm_writel(dwc, dwc->ctx[i].cnt2, DWC_TIM_LD_CNT2(i));
- dwc_pwm_writel(dwc, dwc->ctx[i].ctrl, DWC_TIM_CTRL(i));
- }
-
- return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(dwc_pwm_pm_ops, dwc_pwm_suspend, dwc_pwm_resume);
-
-static const struct pci_device_id dwc_pwm_id_table[] = {
- { PCI_VDEVICE(INTEL, 0x4bb7) }, /* Elkhart Lake */
- { } /* Terminating Entry */
-};
-MODULE_DEVICE_TABLE(pci, dwc_pwm_id_table);
-
-static struct pci_driver dwc_pwm_driver = {
- .name = "pwm-dwc",
- .probe = dwc_pwm_probe,
- .remove = dwc_pwm_remove,
- .id_table = dwc_pwm_id_table,
- .driver = {
- .pm = &dwc_pwm_pm_ops,
- },
-};
-
-module_pci_driver(dwc_pwm_driver);
+EXPORT_SYMBOL_GPL(dwc_pwm_alloc);

MODULE_AUTHOR("Felipe Balbi (Intel)");
MODULE_AUTHOR("Jarkko Nikula <[email protected]>");
diff --git a/drivers/pwm/pwm-dwc.h b/drivers/pwm/pwm-dwc.h
new file mode 100644
index 000000000000..68f98eb76152
--- /dev/null
+++ b/drivers/pwm/pwm-dwc.h
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DesignWare PWM Controller driver
+ *
+ * Copyright (C) 2018-2020 Intel Corporation
+ *
+ * Author: Felipe Balbi (Intel)
+ * Author: Jarkko Nikula <[email protected]>
+ * Author: Raymond Tan <[email protected]>
+ */
+
+#define DWC_TIM_LD_CNT(n) ((n) * 0x14)
+#define DWC_TIM_LD_CNT2(n) (((n) * 4) + 0xb0)
+#define DWC_TIM_CUR_VAL(n) (((n) * 0x14) + 0x04)
+#define DWC_TIM_CTRL(n) (((n) * 0x14) + 0x08)
+#define DWC_TIM_EOI(n) (((n) * 0x14) + 0x0c)
+#define DWC_TIM_INT_STS(n) (((n) * 0x14) + 0x10)
+
+#define DWC_TIMERS_INT_STS 0xa0
+#define DWC_TIMERS_EOI 0xa4
+#define DWC_TIMERS_RAW_INT_STS 0xa8
+#define DWC_TIMERS_COMP_VERSION 0xac
+
+#define DWC_TIMERS_TOTAL 8
+#define DWC_CLK_PERIOD_NS 10
+
+/* Timer Control Register */
+#define DWC_TIM_CTRL_EN BIT(0)
+#define DWC_TIM_CTRL_MODE BIT(1)
+#define DWC_TIM_CTRL_MODE_FREE (0 << 1)
+#define DWC_TIM_CTRL_MODE_USER (1 << 1)
+#define DWC_TIM_CTRL_INT_MASK BIT(2)
+#define DWC_TIM_CTRL_PWM BIT(3)
+
+struct dwc_pwm_ctx {
+ u32 cnt;
+ u32 cnt2;
+ u32 ctrl;
+};
+
+struct dwc_pwm {
+ struct pwm_chip chip;
+ void __iomem *base;
+ struct dwc_pwm_ctx ctx[DWC_TIMERS_TOTAL];
+};
+#define to_dwc_pwm(p) (container_of((p), struct dwc_pwm, chip))
+
+static inline u32 dwc_pwm_readl(struct dwc_pwm *dwc, u32 offset)
+{
+ return readl(dwc->base + offset);
+}
+
+static inline void dwc_pwm_writel(struct dwc_pwm *dwc, u32 value, u32 offset)
+{
+ writel(value, dwc->base + offset);
+}
+
+extern struct dwc_pwm *dwc_pwm_alloc(struct device *dev);
--
2.35.1

2022-08-16 22:12:42

by Ben Dooks

[permalink] [raw]
Subject: [RFC v4 08/10] pwm: dwc: add of/platform support

The dwc pwm controller can be used in non-PCI systems, so allow
either platform or OF based probing.

Signed-off-by: Ben Dooks <[email protected]>
---
v4:
- split the of code out of the core
- moved the compile test code earlier
- fixed review comments
- used NS_PER_SEC
- use devm_clk_get_enabled
v3:
- changed compatible name
---
drivers/pwm/Kconfig | 9 +++++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-dwc-of.c | 78 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 88 insertions(+)
create mode 100644 drivers/pwm/pwm-dwc-of.c

diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index a9f1c554db2b..f1735653365f 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -192,6 +192,15 @@ config PWM_DWC_PCI
To compile this driver as a module, choose M here: the module
will be called pwm-dwc-pci.

+config PWM_DWC_OF
+ tristate "DesignWare PWM Controller (OF bus)
+ depends on PWM_DWC && OF
+ help
+ PWM driver for Synopsys DWC PWM Controller on an OF bus.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-dwc-of.
+
config PWM_EP93XX
tristate "Cirrus Logic EP93xx PWM support"
depends on ARCH_EP93XX || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a70d36623129..d1fd1641f077 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
obj-$(CONFIG_PWM_CRC) += pwm-crc.o
obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
+obj-$(CONFIG_PWM_DWC_OF) += pwm-dwc-of.o
obj-$(CONFIG_PWM_DWC_PCI) += pwm-dwc-pci.o
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
diff --git a/drivers/pwm/pwm-dwc-of.c b/drivers/pwm/pwm-dwc-of.c
new file mode 100644
index 000000000000..d18fac287325
--- /dev/null
+++ b/drivers/pwm/pwm-dwc-of.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DesignWare PWM Controller driver OF
+ *
+ * Copyright (C) 2022 SiFive, Inc.
+ */
+
+#include <linux/bitops.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/io.h>
+
+#include "pwm-dwc.h"
+
+static int dwc_pwm_plat_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct dwc_pwm *dwc;
+ int ret;
+
+ dwc = dwc_pwm_alloc(dev);
+ if (!dwc)
+ return -ENOMEM;
+
+ dwc->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dwc->base))
+ return dev_err_probe(dev, PTR_ERR(dwc->base),
+ "failed to map IO\n");
+
+ dwc->clk = devm_clk_get_enabled(dev, "timer");
+ if (IS_ERR(dwc->clk))
+ return dev_err_probe(dev, PTR_ERR(dwc->clk),
+ "failed to get timer clock\n");
+
+ clk_prepare_enable(dwc->clk);
+ dwc->clk_ns = NSEC_PER_SEC / clk_get_rate(dwc->clk);
+
+ ret = devm_pwmchip_add(dev, &dwc->chip);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int dwc_pwm_plat_remove(struct platform_device *pdev)
+{
+ struct dwc_pwm *dwc = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(dwc->clk);
+ return 0;
+}
+
+static const struct of_device_id dwc_pwm_dt_ids[] = {
+ { .compatible = "snps,dw-apb-timers-pwm2" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, dwc_pwm_dt_ids);
+
+static struct platform_driver dwc_pwm_plat_driver = {
+ .driver = {
+ .name = "dwc-pwm",
+ .of_match_table = dwc_pwm_dt_ids,
+ },
+ .probe = dwc_pwm_plat_probe,
+ .remove = dwc_pwm_plat_remove,
+};
+
+module_platform_driver(dwc_pwm_plat_driver);
+
+MODULE_ALIAS("platform:dwc-pwm-of");
+MODULE_AUTHOR("Ben Dooks <[email protected]>");
+MODULE_DESCRIPTION("DesignWare PWM Controller");
+MODULE_LICENSE("GPL");
--
2.35.1

2022-08-19 14:24:03

by Jarkko Nikula

[permalink] [raw]
Subject: Re: [RFC v4 06/10] pwm: dwc: split pci out of core driver

Hi

On 8/17/22 00:14, Ben Dooks wrote:
> Moving towards adding non-pci support for the driver, move the pci
> parts out of the core into their own module. This is partly due to
> the module_driver() code only being allowed once in a module and also
> to avoid a number of #ifdef if we build a single file in a system
> without pci support.
>
> Signed-off-by: Ben Dooks <[email protected]>
> ---

I quickly tested this on Intel Elkhart and didn't notice any regression.
A few comments below.

> drivers/pwm/Kconfig | 14 +++-
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-dwc-pci.c | 133 ++++++++++++++++++++++++++++++++
> drivers/pwm/pwm-dwc.c | 158 +-------------------------------------
> drivers/pwm/pwm-dwc.h | 58 ++++++++++++++
> 5 files changed, 207 insertions(+), 157 deletions(-)
> create mode 100644 drivers/pwm/pwm-dwc-pci.c
> create mode 100644 drivers/pwm/pwm-dwc.h
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 3f3c53af4a56..a9f1c554db2b 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -175,15 +175,23 @@ config PWM_CROS_EC
> Controller.
>
> config PWM_DWC
> - tristate "DesignWare PWM Controller"
> - depends on PCI || COMPILE_TEST
> + tristate "DesignWare PWM Controller core"
> depends on HAS_IOMEM
> help
> - PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
> + PWM driver for Synopsys DWC PWM Controller.
>
> To compile this driver as a module, choose M here: the module
> will be called pwm-dwc.
>
> +config PWM_DWC_PCI
> + tristate "DesignWare PWM Controller core"

Same text as core part has. How about "DesignWare PWM Controller PCI
driver"?

> + depends on PWM_DWC && HAS_IOMEM && PCI
> + help
> + PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-dwc-pci.
> +
> config PWM_EP93XX
> tristate "Cirrus Logic EP93xx PWM support"
> depends on ARCH_EP93XX || COMPILE_TEST
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 7bf1a29f02b8..a70d36623129 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
> obj-$(CONFIG_PWM_CRC) += pwm-crc.o
> obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
> obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
> +obj-$(CONFIG_PWM_DWC_PCI) += pwm-dwc-pci.o
> obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
> obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
> obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o
> diff --git a/drivers/pwm/pwm-dwc-pci.c b/drivers/pwm/pwm-dwc-pci.c
> new file mode 100644
> index 000000000000..2213d0e7f3c8
> --- /dev/null
> +++ b/drivers/pwm/pwm-dwc-pci.c
> @@ -0,0 +1,133 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * DesignWare PWM Controller driver (PCI part)
> + *
> + * Copyright (C) 2018-2020 Intel Corporation
> + *
> + * Author: Felipe Balbi (Intel)
> + * Author: Jarkko Nikula <[email protected]>
> + * Author: Raymond Tan <[email protected]>
> + *
> + * Limitations:
> + * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low
> + * periods are one or more input clock periods long.
> + */
> +

I think this is more common limitation rather than PCI part.

> --- a/drivers/pwm/pwm-dwc.c
> +++ b/drivers/pwm/pwm-dwc.c
> @@ -1,16 +1,12 @@
> // SPDX-License-Identifier: GPL-2.0
> /*
> - * DesignWare PWM Controller driver
> + * DesignWare PWM Controller driver core
> *
> * Copyright (C) 2018-2020 Intel Corporation
> *
> * Author: Felipe Balbi (Intel)
> * Author: Jarkko Nikula <[email protected]>
> * Author: Raymond Tan <[email protected]>
> - *
> - * Limitations:
> - * - The hardware cannot generate a 0 % or 100 % duty cycle. Both high and low
> - * periods are one or more input clock periods long.
> */

Relates to previous comment, is there reason why this limitation is
removed from the core part?

> --- /dev/null
> +++ b/drivers/pwm/pwm-dwc.h
> +#define DWC_CLK_PERIOD_NS 10

Perhaps this addition can be removed if patch 7/10 goes before this
patch? It's anyway specific to PCI part only.

2022-08-19 17:42:14

by Ben Dooks

[permalink] [raw]
Subject: Re: [RFC v4 06/10] pwm: dwc: split pci out of core driver

On 19/08/2022 14:38, Jarkko Nikula wrote:
> Hi
>
> On 8/17/22 00:14, Ben Dooks wrote:
>> Moving towards adding non-pci support for the driver, move the pci
>> parts out of the core into their own module. This is partly due to
>> the module_driver() code only being allowed once in a module and also
>> to avoid a number of #ifdef if we build a single file in a system
>> without pci support.
>>
>> Signed-off-by: Ben Dooks <[email protected]>
>> ---
>
> I quickly tested this on Intel Elkhart and didn't notice any regression.
> A few comments below.
>
>>   drivers/pwm/Kconfig       |  14 +++-
>>   drivers/pwm/Makefile      |   1 +
>>   drivers/pwm/pwm-dwc-pci.c | 133 ++++++++++++++++++++++++++++++++
>>   drivers/pwm/pwm-dwc.c     | 158 +-------------------------------------
>>   drivers/pwm/pwm-dwc.h     |  58 ++++++++++++++
>>   5 files changed, 207 insertions(+), 157 deletions(-)
>>   create mode 100644 drivers/pwm/pwm-dwc-pci.c
>>   create mode 100644 drivers/pwm/pwm-dwc.h
>>
>> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
>> index 3f3c53af4a56..a9f1c554db2b 100644
>> --- a/drivers/pwm/Kconfig
>> +++ b/drivers/pwm/Kconfig
>> @@ -175,15 +175,23 @@ config PWM_CROS_EC
>>         Controller.
>>   config PWM_DWC
>> -    tristate "DesignWare PWM Controller"
>> -    depends on PCI || COMPILE_TEST
>> +    tristate "DesignWare PWM Controller core"
>>       depends on HAS_IOMEM
>>       help
>> -      PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
>> +      PWM driver for Synopsys DWC PWM Controller.
>>         To compile this driver as a module, choose M here: the module
>>         will be called pwm-dwc.
>> +config PWM_DWC_PCI
>> +    tristate "DesignWare PWM Controller core"
>
> Same text as core part has. How about "DesignWare PWM Controller PCI
> driver"?

Thanks, did notice a couple of kconfig issues so will look at that.

>
>> +    depends on PWM_DWC && HAS_IOMEM && PCI
>> +    help
>> +      PWM driver for Synopsys DWC PWM Controller attached to a PCI bus.
>> +
>> +      To compile this driver as a module, choose M here: the module
>> +      will be called pwm-dwc-pci.
>> +
>>   config PWM_EP93XX
>>       tristate "Cirrus Logic EP93xx PWM support"
>>       depends on ARCH_EP93XX || COMPILE_TEST
>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>> index 7bf1a29f02b8..a70d36623129 100644
>> --- a/drivers/pwm/Makefile
>> +++ b/drivers/pwm/Makefile
>> @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X)    += pwm-clps711x.o
>>   obj-$(CONFIG_PWM_CRC)        += pwm-crc.o
>>   obj-$(CONFIG_PWM_CROS_EC)    += pwm-cros-ec.o
>>   obj-$(CONFIG_PWM_DWC)        += pwm-dwc.o
>> +obj-$(CONFIG_PWM_DWC_PCI)    += pwm-dwc-pci.o
>>   obj-$(CONFIG_PWM_EP93XX)    += pwm-ep93xx.o
>>   obj-$(CONFIG_PWM_FSL_FTM)    += pwm-fsl-ftm.o
>>   obj-$(CONFIG_PWM_HIBVT)        += pwm-hibvt.o
>> diff --git a/drivers/pwm/pwm-dwc-pci.c b/drivers/pwm/pwm-dwc-pci.c
>> new file mode 100644
>> index 000000000000..2213d0e7f3c8
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-dwc-pci.c
>> @@ -0,0 +1,133 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * DesignWare PWM Controller driver (PCI part)
>> + *
>> + * Copyright (C) 2018-2020 Intel Corporation
>> + *
>> + * Author: Felipe Balbi (Intel)
>> + * Author: Jarkko Nikula <[email protected]>
>> + * Author: Raymond Tan <[email protected]>
>> + *
>> + * Limitations:
>> + * - The hardware cannot generate a 0 % or 100 % duty cycle. Both
>> high and low
>> + *   periods are one or more input clock periods long.
>> + */
>> +
>
> I think this is more common limitation rather than PCI part.

The PCI is based off an core without the support, it is added
as a build option as of (IIRC) the 2.13 core.

>
>> --- a/drivers/pwm/pwm-dwc.c
>> +++ b/drivers/pwm/pwm-dwc.c
>> @@ -1,16 +1,12 @@
>>   // SPDX-License-Identifier: GPL-2.0
>>   /*
>> - * DesignWare PWM Controller driver
>> + * DesignWare PWM Controller driver core
>>    *
>>    * Copyright (C) 2018-2020 Intel Corporation
>>    *
>>    * Author: Felipe Balbi (Intel)
>>    * Author: Jarkko Nikula <[email protected]>
>>    * Author: Raymond Tan <[email protected]>
>> - *
>> - * Limitations:
>> - * - The hardware cannot generate a 0 % or 100 % duty cycle. Both
>> high and low
>> - *   periods are one or more input clock periods long.
>>    */
>
> Relates to previous comment, is there reason why this limitation is
> removed from the core part?

See above.

>
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-dwc.h
>> +#define DWC_CLK_PERIOD_NS    10
>
> Perhaps this addition can be removed if patch 7/10 goes before this
> patch? It's anyway specific to PCI part only.

Will look into that

2022-09-14 17:44:29

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [RFC v4 08/10] pwm: dwc: add of/platform support

On Tue, Aug 16, 2022 at 10:14:52PM +0100, Ben Dooks wrote:
> The dwc pwm controller can be used in non-PCI systems, so allow
> either platform or OF based probing.
>
> Signed-off-by: Ben Dooks <[email protected]>
> ---
> v4:
> - split the of code out of the core
> - moved the compile test code earlier
> - fixed review comments
> - used NS_PER_SEC
> - use devm_clk_get_enabled
> v3:
> - changed compatible name
> ---
> drivers/pwm/Kconfig | 9 +++++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-dwc-of.c | 78 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 88 insertions(+)
> create mode 100644 drivers/pwm/pwm-dwc-of.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index a9f1c554db2b..f1735653365f 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -192,6 +192,15 @@ config PWM_DWC_PCI
> To compile this driver as a module, choose M here: the module
> will be called pwm-dwc-pci.
>
> +config PWM_DWC_OF
> + tristate "DesignWare PWM Controller (OF bus)
> + depends on PWM_DWC && OF
> + help
> + PWM driver for Synopsys DWC PWM Controller on an OF bus.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-dwc-of.
> +
> config PWM_EP93XX
> tristate "Cirrus Logic EP93xx PWM support"
> depends on ARCH_EP93XX || COMPILE_TEST
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index a70d36623129..d1fd1641f077 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
> obj-$(CONFIG_PWM_CRC) += pwm-crc.o
> obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
> obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
> +obj-$(CONFIG_PWM_DWC_OF) += pwm-dwc-of.o
> obj-$(CONFIG_PWM_DWC_PCI) += pwm-dwc-pci.o
> obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
> obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
> diff --git a/drivers/pwm/pwm-dwc-of.c b/drivers/pwm/pwm-dwc-of.c
> new file mode 100644
> index 000000000000..d18fac287325
> --- /dev/null
> +++ b/drivers/pwm/pwm-dwc-of.c
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * DesignWare PWM Controller driver OF
> + *
> + * Copyright (C) 2022 SiFive, Inc.
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/export.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/pwm.h>
> +#include <linux/io.h>
> +
> +#include "pwm-dwc.h"
> +
> +static int dwc_pwm_plat_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct dwc_pwm *dwc;
> + int ret;
> +
> + dwc = dwc_pwm_alloc(dev);
> + if (!dwc)
> + return -ENOMEM;
> +
> + dwc->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(dwc->base))
> + return dev_err_probe(dev, PTR_ERR(dwc->base),
> + "failed to map IO\n");

devm_platform_ioremap_resource() already emits an error message.

> +
> + dwc->clk = devm_clk_get_enabled(dev, "timer");
> + if (IS_ERR(dwc->clk))
> + return dev_err_probe(dev, PTR_ERR(dwc->clk),
> + "failed to get timer clock\n");
> +
> + clk_prepare_enable(dwc->clk);

You don't need clk_prepare_enable() as you used devm_clk_get_enabled().

(Otherwise, when keeping clk_prepare_enable() you need to check the
return value.)

> + dwc->clk_ns = NSEC_PER_SEC / clk_get_rate(dwc->clk);

I think I already pointed out this is non-optimal.

Later you use clk_ns in __dwc_pwm_configure_timer():

tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);

So what you really want here is:

tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * clk_get_rate(dwc->clk), NSEC_PER_SEC);

With for example clk_get_rate(dwc->clk) = 201171875 and duty_cycle =
4096 you now get clk_ns = 4 (while the exact value is 4.97087..), tmp =
1024, while the exact value is 824.

So the idea is to add a clkrate member to the private driver struct, let
it default to 100000000 for the pci case and use the line I suggested
above.

> +
> + ret = devm_pwmchip_add(dev, &dwc->chip);
> + if (ret)
> + return ret;
> +
> + return 0;

This is equivalent to

return ret;

> +}
> +
> +static int dwc_pwm_plat_remove(struct platform_device *pdev)
> +{
> + struct dwc_pwm *dwc = platform_get_drvdata(pdev);
> +
> + clk_disable_unprepare(dwc->clk);
> + return 0;
> +}

When dropping clk_prepare_enable() the .remove callback can go away,
too.

> +
> +static const struct of_device_id dwc_pwm_dt_ids[] = {
> + { .compatible = "snps,dw-apb-timers-pwm2" },
> + { },
> +};
> +MODULE_DEVICE_TABLE(of, dwc_pwm_dt_ids);
> +
> +static struct platform_driver dwc_pwm_plat_driver = {
> + .driver = {
> + .name = "dwc-pwm",
> + .of_match_table = dwc_pwm_dt_ids,
> + },
> + .probe = dwc_pwm_plat_probe,
> + .remove = dwc_pwm_plat_remove,
> +};
> +
> +module_platform_driver(dwc_pwm_plat_driver);
> +
> +MODULE_ALIAS("platform:dwc-pwm-of");
> +MODULE_AUTHOR("Ben Dooks <[email protected]>");
> +MODULE_DESCRIPTION("DesignWare PWM Controller");
> +MODULE_LICENSE("GPL");

Best regards
Uwe

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


Attachments:
(No filename) (5.27 kB)
signature.asc (499.00 B)
Download all attachments

2022-09-15 07:37:51

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [RFC v4 08/10] pwm: dwc: add of/platform support

Hello,

On Tue, Aug 16, 2022 at 10:14:52PM +0100, Ben Dooks wrote:
> The dwc pwm controller can be used in non-PCI systems, so allow
> either platform or OF based probing.
>
> Signed-off-by: Ben Dooks <[email protected]>
> ---
> v4:
> - split the of code out of the core
> - moved the compile test code earlier
> - fixed review comments
> - used NS_PER_SEC
> - use devm_clk_get_enabled
> v3:
> - changed compatible name
> ---
> drivers/pwm/Kconfig | 9 +++++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-dwc-of.c | 78 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 88 insertions(+)
> create mode 100644 drivers/pwm/pwm-dwc-of.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index a9f1c554db2b..f1735653365f 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -192,6 +192,15 @@ config PWM_DWC_PCI
> To compile this driver as a module, choose M here: the module
> will be called pwm-dwc-pci.
>
> +config PWM_DWC_OF
> + tristate "DesignWare PWM Controller (OF bus)

There is a missing " which results in:

drivers/pwm/Kconfig:196:warning: multi-line strings not supported

Best regards
Uwe

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


Attachments:
(No filename) (1.34 kB)
signature.asc (499.00 B)
Download all attachments

2022-09-19 22:15:18

by Ben Dooks

[permalink] [raw]
Subject: Re: [RFC v4 08/10] pwm: dwc: add of/platform support

On 15/09/2022 08:24, Uwe Kleine-König wrote:
> Hello,
>
> On Tue, Aug 16, 2022 at 10:14:52PM +0100, Ben Dooks wrote:
>> The dwc pwm controller can be used in non-PCI systems, so allow
>> either platform or OF based probing.
>>
>> Signed-off-by: Ben Dooks <[email protected]>
>> ---
>> v4:
>> - split the of code out of the core
>> - moved the compile test code earlier
>> - fixed review comments
>> - used NS_PER_SEC
>> - use devm_clk_get_enabled
>> v3:
>> - changed compatible name
>> ---
>> drivers/pwm/Kconfig | 9 +++++
>> drivers/pwm/Makefile | 1 +
>> drivers/pwm/pwm-dwc-of.c | 78 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 88 insertions(+)
>> create mode 100644 drivers/pwm/pwm-dwc-of.c
>>
>> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
>> index a9f1c554db2b..f1735653365f 100644
>> --- a/drivers/pwm/Kconfig
>> +++ b/drivers/pwm/Kconfig
>> @@ -192,6 +192,15 @@ config PWM_DWC_PCI
>> To compile this driver as a module, choose M here: the module
>> will be called pwm-dwc-pci.
>>
>> +config PWM_DWC_OF
>> + tristate "DesignWare PWM Controller (OF bus)
>
> There is a missing " which results in:
>
> drivers/pwm/Kconfig:196:warning: multi-line strings not supported
>
> Best regards
> Uwe

Thanks, fixed.

2022-09-19 23:13:38

by Ben Dooks

[permalink] [raw]
Subject: Re: [RFC v4 08/10] pwm: dwc: add of/platform support

On 14/09/2022 17:47, Uwe Kleine-König wrote:
> On Tue, Aug 16, 2022 at 10:14:52PM +0100, Ben Dooks wrote:
>> The dwc pwm controller can be used in non-PCI systems, so allow
>> either platform or OF based probing.
>>
>> Signed-off-by: Ben Dooks <[email protected]>
>> ---
>> v4:
>> - split the of code out of the core
>> - moved the compile test code earlier
>> - fixed review comments
>> - used NS_PER_SEC
>> - use devm_clk_get_enabled
>> v3:
>> - changed compatible name
>> ---
>> drivers/pwm/Kconfig | 9 +++++
>> drivers/pwm/Makefile | 1 +
>> drivers/pwm/pwm-dwc-of.c | 78 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 88 insertions(+)
>> create mode 100644 drivers/pwm/pwm-dwc-of.c
>>
>> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
>> index a9f1c554db2b..f1735653365f 100644
>> --- a/drivers/pwm/Kconfig
>> +++ b/drivers/pwm/Kconfig
>> @@ -192,6 +192,15 @@ config PWM_DWC_PCI
>> To compile this driver as a module, choose M here: the module
>> will be called pwm-dwc-pci.
>>
>> +config PWM_DWC_OF
>> + tristate "DesignWare PWM Controller (OF bus)
>> + depends on PWM_DWC && OF
>> + help
>> + PWM driver for Synopsys DWC PWM Controller on an OF bus.
>> +
>> + To compile this driver as a module, choose M here: the module
>> + will be called pwm-dwc-of.
>> +
>> config PWM_EP93XX
>> tristate "Cirrus Logic EP93xx PWM support"
>> depends on ARCH_EP93XX || COMPILE_TEST
>> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
>> index a70d36623129..d1fd1641f077 100644
>> --- a/drivers/pwm/Makefile
>> +++ b/drivers/pwm/Makefile
>> @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
>> obj-$(CONFIG_PWM_CRC) += pwm-crc.o
>> obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o
>> obj-$(CONFIG_PWM_DWC) += pwm-dwc.o
>> +obj-$(CONFIG_PWM_DWC_OF) += pwm-dwc-of.o
>> obj-$(CONFIG_PWM_DWC_PCI) += pwm-dwc-pci.o
>> obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
>> obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
>> diff --git a/drivers/pwm/pwm-dwc-of.c b/drivers/pwm/pwm-dwc-of.c
>> new file mode 100644
>> index 000000000000..d18fac287325
>> --- /dev/null
>> +++ b/drivers/pwm/pwm-dwc-of.c
>> @@ -0,0 +1,78 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * DesignWare PWM Controller driver OF
>> + *
>> + * Copyright (C) 2022 SiFive, Inc.
>> + */
>> +
>> +#include <linux/bitops.h>
>> +#include <linux/export.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/clk.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/pwm.h>
>> +#include <linux/io.h>
>> +
>> +#include "pwm-dwc.h"
>> +
>> +static int dwc_pwm_plat_probe(struct platform_device *pdev)
>> +{
>> + struct device *dev = &pdev->dev;
>> + struct dwc_pwm *dwc;
>> + int ret;
>> +
>> + dwc = dwc_pwm_alloc(dev);
>> + if (!dwc)
>> + return -ENOMEM;
>> +
>> + dwc->base = devm_platform_ioremap_resource(pdev, 0);
>> + if (IS_ERR(dwc->base))
>> + return dev_err_probe(dev, PTR_ERR(dwc->base),
>> + "failed to map IO\n");
>
> devm_platform_ioremap_resource() already emits an error message.

ok, fixed


>> +
>> + dwc->clk = devm_clk_get_enabled(dev, "timer");
>> + if (IS_ERR(dwc->clk))
>> + return dev_err_probe(dev, PTR_ERR(dwc->clk),
>> + "failed to get timer clock\n");
>> +
>> + clk_prepare_enable(dwc->clk);
>
> You don't need clk_prepare_enable() as you used devm_clk_get_enabled().
>
> (Otherwise, when keeping clk_prepare_enable() you need to check the
> return value.)

ok, fixed. I didn't notice that when changing to devm_

>
>> + dwc->clk_ns = NSEC_PER_SEC / clk_get_rate(dwc->clk);
>
> I think I already pointed out this is non-optimal.
>
> Later you use clk_ns in __dwc_pwm_configure_timer():
>
> tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, dwc->clk_ns);
>
> So what you really want here is:
>
> tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * clk_get_rate(dwc->clk), NSEC_PER_SEC);
>
> With for example clk_get_rate(dwc->clk) = 201171875 and duty_cycle =
> 4096 you now get clk_ns = 4 (while the exact value is 4.97087..), tmp =
> 1024, while the exact value is 824.
>
> So the idea is to add a clkrate member to the private driver struct, let
> it default to 100000000 for the pci case and use the line I suggested
> above.

ok, will consider keeping the rate in hz and modifiying the pci
version to use 10 * NSEC_PER_SEC for the rate.

I've been trying to avoid changing the pci case, but I think for
anything with a clk pointer we should be doing clk_get_rate in the
calc code

>
>> +
>> + ret = devm_pwmchip_add(dev, &dwc->chip);
>> + if (ret)
>> + return ret;
>> +
>> + return 0;
>
> This is equivalent to
>
> return ret;

Will sort that out.


>> +}
>> +
>> +static int dwc_pwm_plat_remove(struct platform_device *pdev)
>> +{
>> + struct dwc_pwm *dwc = platform_get_drvdata(pdev);
>> +
>> + clk_disable_unprepare(dwc->clk);
>> + return 0;
>> +}
>
> When dropping clk_prepare_enable() the .remove callback can go away,
> too.

thanks, spotted that one a while ago.

>> +
>> +static const struct of_device_id dwc_pwm_dt_ids[] = {
>> + { .compatible = "snps,dw-apb-timers-pwm2" },
>> + { },
>> +};
>> +MODULE_DEVICE_TABLE(of, dwc_pwm_dt_ids);
>> +
>> +static struct platform_driver dwc_pwm_plat_driver = {
>> + .driver = {
>> + .name = "dwc-pwm",
>> + .of_match_table = dwc_pwm_dt_ids,
>> + },
>> + .probe = dwc_pwm_plat_probe,
>> + .remove = dwc_pwm_plat_remove,
>> +};
>> +
>> +module_platform_driver(dwc_pwm_plat_driver);
>> +
>> +MODULE_ALIAS("platform:dwc-pwm-of");
>> +MODULE_AUTHOR("Ben Dooks <[email protected]>");
>> +MODULE_DESCRIPTION("DesignWare PWM Controller");
>> +MODULE_LICENSE("GPL");
>
> Best regards
> Uwe
>

2022-09-27 17:21:58

by Uwe Kleine-König

[permalink] [raw]
Subject: Re: [RFC v4 00/10] RFC on synpsys pwm driver changes

Hello Ben,

there was some feedback to individual patches that require a rework. I'm
marking the whole series as "changes requested" in the expectation that
you will resend them all once you addressed the feedback.

Best regards
Uwe

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


Attachments:
(No filename) (400.00 B)
signature.asc (499.00 B)
Download all attachments

2022-09-27 19:18:25

by Ben Dooks

[permalink] [raw]
Subject: Re: [RFC v4 00/10] RFC on synpsys pwm driver changes

On 27/09/2022 17:47, Uwe Kleine-König wrote:
> Hello Ben,
>
> there was some feedback to individual patches that require a rework. I'm
> marking the whole series as "changes requested" in the expectation that
> you will resend them all once you addressed the feedback.

I have most of the feedback done but we've not had a chance to test them
fully. I can send a new series later today but the changes for the clock
division calculations have yet to be tested.

--
Ben