From 2e379ffb44d948515dbdddf061a9f0c75cd9d33f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:39 +0000 Subject: [PATCH 01/66] pwm: sun4i: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sun4i.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 38a4c5c1317b..cc1eb0818648 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -395,7 +395,6 @@ MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids); static int sun4i_pwm_probe(struct platform_device *pdev) { struct sun4i_pwm_chip *pwm; - struct resource *res; int ret; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); @@ -406,8 +405,7 @@ static int sun4i_pwm_probe(struct platform_device *pdev) if (!pwm->data) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->base = devm_ioremap_resource(&pdev->dev, res); + pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->base)) return PTR_ERR(pwm->base); From e9534031f0692fb9405c7a606ebba9303de43e11 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:40 +0000 Subject: [PATCH 02/66] pwm: fsl-ftm: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-fsl-ftm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 59272a920479..2a6801226aba 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -399,7 +399,6 @@ static const struct regmap_config fsl_pwm_regmap_config = { static int fsl_pwm_probe(struct platform_device *pdev) { struct fsl_pwm_chip *fpc; - struct resource *res; void __iomem *base; int ret; @@ -412,8 +411,7 @@ static int fsl_pwm_probe(struct platform_device *pdev) fpc->soc = of_device_get_match_data(&pdev->dev); fpc->chip.dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From 3d3a32593957da447a27520beefb1834ba068a57 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:41 +0000 Subject: [PATCH 03/66] pwm: rcar: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rcar.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 7ab9eb6616d9..3e23f1e4e1f6 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -204,15 +204,13 @@ static const struct pwm_ops rcar_pwm_ops = { static int rcar_pwm_probe(struct platform_device *pdev) { struct rcar_pwm_chip *rcar_pwm; - struct resource *res; int ret; rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL); if (rcar_pwm == NULL) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rcar_pwm->base = devm_ioremap_resource(&pdev->dev, res); + rcar_pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(rcar_pwm->base)) return PTR_ERR(rcar_pwm->base); From e3f22bc2556abd445bc15decd864c85f4444c870 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:42 +0000 Subject: [PATCH 04/66] pwm: renesas-tpu: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-renesas-tpu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index 81ad5a551455..d02b24b77cdf 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -383,7 +383,6 @@ static const struct pwm_ops tpu_pwm_ops = { static int tpu_probe(struct platform_device *pdev) { struct tpu_device *tpu; - struct resource *res; int ret; tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL); @@ -394,8 +393,7 @@ static int tpu_probe(struct platform_device *pdev) tpu->pdev = pdev; /* Map memory, get clock and pin control. */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - tpu->base = devm_ioremap_resource(&pdev->dev, res); + tpu->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(tpu->base)) return PTR_ERR(tpu->base); From fc0155f8221ab47c2d02c52f15a4699403d9cdde Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:43 +0000 Subject: [PATCH 05/66] pwm: ep93xx: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ep93xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index 4bab73073ad7..c9fc6f223640 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -169,15 +169,13 @@ static const struct pwm_ops ep93xx_pwm_ops = { static int ep93xx_pwm_probe(struct platform_device *pdev) { struct ep93xx_pwm *ep93xx_pwm; - struct resource *res; int ret; ep93xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_pwm), GFP_KERNEL); if (!ep93xx_pwm) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ep93xx_pwm->base = devm_ioremap_resource(&pdev->dev, res); + ep93xx_pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ep93xx_pwm->base)) return PTR_ERR(ep93xx_pwm->base); From fa44fe41cc75523b835bf6f625ee1cbf3d0c566b Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:44 +0000 Subject: [PATCH 06/66] pwm: tegra: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tegra.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 1daf591025c0..55bc63d5a0ae 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -237,7 +237,6 @@ static const struct pwm_ops tegra_pwm_ops = { static int tegra_pwm_probe(struct platform_device *pdev) { struct tegra_pwm_chip *pwm; - struct resource *r; int ret; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); @@ -247,8 +246,7 @@ static int tegra_pwm_probe(struct platform_device *pdev) pwm->soc = of_device_get_match_data(&pdev->dev); pwm->dev = &pdev->dev; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->regs = devm_ioremap_resource(&pdev->dev, r); + pwm->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->regs)) return PTR_ERR(pwm->regs); From 7681c2bd2ab2dd1470793694cadcf3487282ffae Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:45 +0000 Subject: [PATCH 07/66] pwm: mediatek: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index ab001ce55178..6bc851cadb3e 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -208,7 +208,6 @@ static const struct pwm_ops pwm_mediatek_ops = { static int pwm_mediatek_probe(struct platform_device *pdev) { struct pwm_mediatek_chip *pc; - struct resource *res; unsigned int i; int ret; @@ -218,8 +217,7 @@ static int pwm_mediatek_probe(struct platform_device *pdev) pc->soc = of_device_get_match_data(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->regs = devm_ioremap_resource(&pdev->dev, res); + pc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); From 728cd3e6eaf810d49e5a8d8c288fcabda2c81b63 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:46 +0000 Subject: [PATCH 08/66] pwm: sti: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sti.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 1508616d794c..eaeb38c0c0c7 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -540,7 +540,6 @@ static int sti_pwm_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sti_pwm_compat_data *cdata; struct sti_pwm_chip *pc; - struct resource *res; unsigned int i; int irq, ret; @@ -552,9 +551,7 @@ static int sti_pwm_probe(struct platform_device *pdev) if (!cdata) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - pc->mmio = devm_ioremap_resource(dev, res); + pc->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio)) return PTR_ERR(pc->mmio); From 6945fe42f8016352869b40eeb525dd3eb68f4644 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:47 +0000 Subject: [PATCH 09/66] pwm: pxa: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-pxa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-pxa.c b/drivers/pwm/pwm-pxa.c index a2a0912c2dcd..d06cf60e6575 100644 --- a/drivers/pwm/pwm-pxa.c +++ b/drivers/pwm/pwm-pxa.c @@ -166,7 +166,6 @@ static int pwm_probe(struct platform_device *pdev) { const struct platform_device_id *id = platform_get_device_id(pdev); struct pxa_pwm_chip *pwm; - struct resource *r; int ret = 0; if (IS_ENABLED(CONFIG_OF) && id == NULL) @@ -193,8 +192,7 @@ static int pwm_probe(struct platform_device *pdev) pwm->chip.of_pwm_n_cells = 1; } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r); + pwm->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->mmio_base)) return PTR_ERR(pwm->mmio_base); From bde048ebbd2730f569dadfc431a9de1678593941 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:48 +0000 Subject: [PATCH 10/66] pwm: zx: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-zx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-zx.c b/drivers/pwm/pwm-zx.c index e2c21cc34a96..0f5e8919b034 100644 --- a/drivers/pwm/pwm-zx.c +++ b/drivers/pwm/pwm-zx.c @@ -196,7 +196,6 @@ static const struct pwm_ops zx_pwm_ops = { static int zx_pwm_probe(struct platform_device *pdev) { struct zx_pwm_chip *zpc; - struct resource *res; unsigned int i; int ret; @@ -204,8 +203,7 @@ static int zx_pwm_probe(struct platform_device *pdev) if (!zpc) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - zpc->base = devm_ioremap_resource(&pdev->dev, res); + zpc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(zpc->base)) return PTR_ERR(zpc->base); From 21af435676d3a4a339420aa122f6a82e0d8ea650 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:49 +0000 Subject: [PATCH 11/66] pwm: spear: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-spear.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-spear.c b/drivers/pwm/pwm-spear.c index 6c6b44fd3f43..f63b54aae1b4 100644 --- a/drivers/pwm/pwm-spear.c +++ b/drivers/pwm/pwm-spear.c @@ -174,7 +174,6 @@ static int spear_pwm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct spear_pwm_chip *pc; - struct resource *r; int ret; u32 val; @@ -182,8 +181,7 @@ static int spear_pwm_probe(struct platform_device *pdev) if (!pc) return -ENOMEM; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); + pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio_base)) return PTR_ERR(pc->mmio_base); From 537fe68786738ebc48083fad2f057220a9ba8464 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:50 +0000 Subject: [PATCH 12/66] pwm: bcm-kona: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm-kona.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 16c5898b934a..578b3621c97e 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -259,7 +259,6 @@ static const struct pwm_ops kona_pwm_ops = { static int kona_pwmc_probe(struct platform_device *pdev) { struct kona_pwmc *kp; - struct resource *res; unsigned int chan; unsigned int value = 0; int ret = 0; @@ -277,8 +276,7 @@ static int kona_pwmc_probe(struct platform_device *pdev) kp->chip.of_xlate = of_pwm_xlate_with_flags; kp->chip.of_pwm_n_cells = 3; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - kp->base = devm_ioremap_resource(&pdev->dev, res); + kp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kp->base)) return PTR_ERR(kp->base); From fd7c575ac6026e078fa30dc237d3e86897c58652 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:51 +0000 Subject: [PATCH 13/66] pwm: lpc32xx: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpc32xx.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-lpc32xx.c b/drivers/pwm/pwm-lpc32xx.c index 710d9a207d2b..6b4090436c06 100644 --- a/drivers/pwm/pwm-lpc32xx.c +++ b/drivers/pwm/pwm-lpc32xx.c @@ -98,7 +98,6 @@ static const struct pwm_ops lpc32xx_pwm_ops = { static int lpc32xx_pwm_probe(struct platform_device *pdev) { struct lpc32xx_pwm_chip *lpc32xx; - struct resource *res; int ret; u32 val; @@ -106,8 +105,7 @@ static int lpc32xx_pwm_probe(struct platform_device *pdev) if (!lpc32xx) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - lpc32xx->base = devm_ioremap_resource(&pdev->dev, res); + lpc32xx->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(lpc32xx->base)) return PTR_ERR(lpc32xx->base); From 17076b10d40a612a7fe1c41b4bcc1c9701f14cdc Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:52 +0000 Subject: [PATCH 14/66] pwm: meson: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Martin Blumenstingl Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-meson.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index bd0d7336b898..a3ce9789412a 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -537,15 +537,13 @@ static int meson_pwm_init_channels(struct meson_pwm *meson) static int meson_pwm_probe(struct platform_device *pdev) { struct meson_pwm *meson; - struct resource *regs; int err; meson = devm_kzalloc(&pdev->dev, sizeof(*meson), GFP_KERNEL); if (!meson) return -ENOMEM; - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - meson->base = devm_ioremap_resource(&pdev->dev, regs); + meson->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(meson->base)) return PTR_ERR(meson->base); From 5119ee9effdd44c5ceaf6f63bd542dfb4a58f4c0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:53 +0000 Subject: [PATCH 15/66] pwm: rockchip: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Heiko Stuebner Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rockchip.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 77c23a2c6d71..389a5e140412 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -287,7 +287,6 @@ static int rockchip_pwm_probe(struct platform_device *pdev) { const struct of_device_id *id; struct rockchip_pwm_chip *pc; - struct resource *r; u32 enable_conf, ctrl; int ret, count; @@ -299,8 +298,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) if (!pc) return -ENOMEM; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->base = devm_ioremap_resource(&pdev->dev, r); + pc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->base)) return PTR_ERR(pc->base); From ed98401f466507f6fd73da5bbedb5bf7f74b4467 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:54 +0000 Subject: [PATCH 16/66] pwm: bcm-iproc: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm-iproc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index 79b1e58e946d..f4853c4a2d75 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -197,7 +197,6 @@ static const struct pwm_ops iproc_pwm_ops = { static int iproc_pwmc_probe(struct platform_device *pdev) { struct iproc_pwmc *ip; - struct resource *res; unsigned int i; u32 value; int ret; @@ -215,8 +214,7 @@ static int iproc_pwmc_probe(struct platform_device *pdev) ip->chip.of_xlate = of_pwm_xlate_with_flags; ip->chip.of_pwm_n_cells = 3; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ip->base = devm_ioremap_resource(&pdev->dev, res); + ip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ip->base)) return PTR_ERR(ip->base); From cc1cc4ba3673913bc12769fc24ea8ed47819077a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:55 +0000 Subject: [PATCH 17/66] pwm: samsung: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-samsung.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-samsung.c b/drivers/pwm/pwm-samsung.c index 87a886f7dc2f..645d0066ff0a 100644 --- a/drivers/pwm/pwm-samsung.c +++ b/drivers/pwm/pwm-samsung.c @@ -510,7 +510,6 @@ static int pwm_samsung_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct samsung_pwm_chip *chip; - struct resource *res; unsigned int chan; int ret; @@ -541,8 +540,7 @@ static int pwm_samsung_probe(struct platform_device *pdev) sizeof(chip->variant)); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->base = devm_ioremap_resource(&pdev->dev, res); + chip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->base)) return PTR_ERR(chip->base); From dc13c0f61e31c9c00b072ba2d851362fbdd25bfa Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:56 +0000 Subject: [PATCH 18/66] pwm: tiehrpwm: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 0846917ff2d2..97dc62fe9175 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -421,7 +421,6 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct ehrpwm_pwm_chip *pc; - struct resource *r; struct clk *clk; int ret; @@ -455,8 +454,7 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) pc->chip.base = -1; pc->chip.npwm = NUM_PWM_CHANNEL; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); + pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio_base)) return PTR_ERR(pc->mmio_base); From 860b1ca0eabc8c2199c5edd9226f214b085c3f9b Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:58 +0000 Subject: [PATCH 19/66] pwm: imx: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx1.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index f8b2c2e001a7..1a60bfd7d659 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -136,7 +136,6 @@ MODULE_DEVICE_TABLE(of, pwm_imx1_dt_ids); static int pwm_imx1_probe(struct platform_device *pdev) { struct pwm_imx1_chip *imx; - struct resource *r; imx = devm_kzalloc(&pdev->dev, sizeof(*imx), GFP_KERNEL); if (!imx) @@ -168,8 +167,7 @@ static int pwm_imx1_probe(struct platform_device *pdev) imx->chip.base = -1; imx->chip.npwm = 1; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - imx->mmio_base = devm_ioremap_resource(&pdev->dev, r); + imx->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(imx->mmio_base)) return PTR_ERR(imx->mmio_base); From 1dcf0523fdb37b0b0d97b07dacce6b99b4d3c0ce Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:05:59 +0000 Subject: [PATCH 20/66] pwm: tiecap: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiecap.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index 683804c7d26c..2a8949014bb1 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -196,7 +196,6 @@ static int ecap_pwm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct ecap_pwm_chip *pc; - struct resource *r; struct clk *clk; int ret; @@ -230,8 +229,7 @@ static int ecap_pwm_probe(struct platform_device *pdev) pc->chip.base = -1; pc->chip.npwm = 1; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->mmio_base = devm_ioremap_resource(&pdev->dev, r); + pc->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->mmio_base)) return PTR_ERR(pc->mmio_base); From f57e7d25e5f3cb8724668c3118aee7d9a00ec7f1 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:00 +0000 Subject: [PATCH 21/66] pwm: bcm2835: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 6841dcfe27fc..bc018daf1488 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -137,7 +137,6 @@ static const struct pwm_ops bcm2835_pwm_ops = { static int bcm2835_pwm_probe(struct platform_device *pdev) { struct bcm2835_pwm *pc; - struct resource *res; int ret; pc = devm_kzalloc(&pdev->dev, sizeof(*pc), GFP_KERNEL); @@ -146,8 +145,7 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) pc->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pc->base = devm_ioremap_resource(&pdev->dev, res); + pc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pc->base)) return PTR_ERR(pc->base); From 05baa59601ee11fdbd0babb4cce49b2ffff7fb14 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:01 +0000 Subject: [PATCH 22/66] pwm: berlin: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-berlin.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index b91c477cc84b..fe405289e582 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -186,15 +186,13 @@ MODULE_DEVICE_TABLE(of, berlin_pwm_match); static int berlin_pwm_probe(struct platform_device *pdev) { struct berlin_pwm_chip *pwm; - struct resource *res; int ret; pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); if (!pwm) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->base = devm_ioremap_resource(&pdev->dev, res); + pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->base)) return PTR_ERR(pwm->base); From 4906bf5482e4965a686ea61f78e87623a792bd8f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:02 +0000 Subject: [PATCH 23/66] pwm: vt8500: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-vt8500.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-vt8500.c b/drivers/pwm/pwm-vt8500.c index 11d45e56a923..6e36851a22bb 100644 --- a/drivers/pwm/pwm-vt8500.c +++ b/drivers/pwm/pwm-vt8500.c @@ -193,7 +193,6 @@ MODULE_DEVICE_TABLE(of, vt8500_pwm_dt_ids); static int vt8500_pwm_probe(struct platform_device *pdev) { struct vt8500_chip *chip; - struct resource *r; struct device_node *np = pdev->dev.of_node; int ret; @@ -219,8 +218,7 @@ static int vt8500_pwm_probe(struct platform_device *pdev) return PTR_ERR(chip->clk); } - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - chip->base = devm_ioremap_resource(&pdev->dev, r); + chip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(chip->base)) return PTR_ERR(chip->base); From 5bec839f13a96eeb787142c36b6da2380a616999 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:03 +0000 Subject: [PATCH 24/66] pwm: brcmstb: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Nicolas Saenz Julienne Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-brcmstb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c index fea612c45f20..8b66f9d2f589 100644 --- a/drivers/pwm/pwm-brcmstb.c +++ b/drivers/pwm/pwm-brcmstb.c @@ -234,7 +234,6 @@ MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match); static int brcmstb_pwm_probe(struct platform_device *pdev) { struct brcmstb_pwm *p; - struct resource *res; int ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); @@ -262,8 +261,7 @@ static int brcmstb_pwm_probe(struct platform_device *pdev) p->chip.base = -1; p->chip.npwm = 2; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - p->base = devm_ioremap_resource(&pdev->dev, res); + p->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(p->base)) { ret = PTR_ERR(p->base); goto out_clk; From 6e0301e7df7a2bd88bf9397c9814d79594ee42e2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:04 +0000 Subject: [PATCH 25/66] pwm: mtk-disp: Convert to devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Matthias Brugger Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mtk-disp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c index 83b8be0209b7..87c6b4bc5d43 100644 --- a/drivers/pwm/pwm-mtk-disp.c +++ b/drivers/pwm/pwm-mtk-disp.c @@ -172,7 +172,6 @@ static const struct pwm_ops mtk_disp_pwm_ops = { static int mtk_disp_pwm_probe(struct platform_device *pdev) { struct mtk_disp_pwm *mdp; - struct resource *r; int ret; mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL); @@ -181,8 +180,7 @@ static int mtk_disp_pwm_probe(struct platform_device *pdev) mdp->data = of_device_get_match_data(&pdev->dev); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mdp->base = devm_ioremap_resource(&pdev->dev, r); + mdp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mdp->base)) return PTR_ERR(mdp->base); From 3151b13017ec727b5a20b2ffe65366602d8305b4 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:05 +0000 Subject: [PATCH 26/66] pwm: clps711x: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-clps711x.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-clps711x.c b/drivers/pwm/pwm-clps711x.c index ba9500aca078..cb1af86873ee 100644 --- a/drivers/pwm/pwm-clps711x.c +++ b/drivers/pwm/pwm-clps711x.c @@ -113,14 +113,12 @@ static struct pwm_device *clps711x_pwm_xlate(struct pwm_chip *chip, static int clps711x_pwm_probe(struct platform_device *pdev) { struct clps711x_chip *priv; - struct resource *res; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->pmpcon = devm_ioremap_resource(&pdev->dev, res); + priv->pmpcon = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(priv->pmpcon)) return PTR_ERR(priv->pmpcon); From d574ab62a56f2499e2976654f9107b17cb9874f2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:06 +0000 Subject: [PATCH 27/66] pwm: img: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-img.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c index a34d95ed70b2..6faf5b5a5584 100644 --- a/drivers/pwm/pwm-img.c +++ b/drivers/pwm/pwm-img.c @@ -240,7 +240,6 @@ static int img_pwm_probe(struct platform_device *pdev) int ret; u64 val; unsigned long clk_rate; - struct resource *res; struct img_pwm_chip *pwm; const struct of_device_id *of_dev_id; @@ -250,8 +249,7 @@ static int img_pwm_probe(struct platform_device *pdev) pwm->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm->base = devm_ioremap_resource(&pdev->dev, res); + pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm->base)) return PTR_ERR(pwm->base); From 74ec20a4e6a064ac2cdfb577c115cb948b307f0f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:07 +0000 Subject: [PATCH 28/66] pwm: lpc18xx-sct: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpc18xx-sct.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c index 5ff11145c1a3..dc5133bec3e7 100644 --- a/drivers/pwm/pwm-lpc18xx-sct.c +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -325,7 +325,6 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) { struct lpc18xx_pwm_chip *lpc18xx_pwm; struct pwm_device *pwm; - struct resource *res; int ret, i; u64 val; @@ -336,8 +335,7 @@ static int lpc18xx_pwm_probe(struct platform_device *pdev) lpc18xx_pwm->dev = &pdev->dev; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - lpc18xx_pwm->base = devm_ioremap_resource(&pdev->dev, res); + lpc18xx_pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(lpc18xx_pwm->base)) return PTR_ERR(lpc18xx_pwm->base); From cecccd8d4af2672725306924cd4987acc6491054 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:08 +0000 Subject: [PATCH 29/66] pwm: hibvt: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. While at it, also declare the "i" and "ret" variables on the same line since they are of the same type. Signed-off-by: Yangtao Li Acked-by: Uwe Kleine-König Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-hibvt.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index ad205fdad372..a1900d0a872e 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -190,9 +190,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev) const struct hibvt_pwm_soc *soc = of_device_get_match_data(&pdev->dev); struct hibvt_pwm_chip *pwm_chip; - struct resource *res; - int ret; - int i; + int ret, i; pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL); if (pwm_chip == NULL) @@ -213,8 +211,7 @@ static int hibvt_pwm_probe(struct platform_device *pdev) pwm_chip->chip.of_pwm_n_cells = 3; pwm_chip->soc = soc; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pwm_chip->base = devm_ioremap_resource(&pdev->dev, res); + pwm_chip->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pwm_chip->base)) return PTR_ERR(pwm_chip->base); From 96cfceba3967198fc5d501d7e1a37122b5c9bf29 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:09 +0000 Subject: [PATCH 30/66] pwm: sifive: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sifive.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index 2485fbaaead2..2a7cd2deaeea 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -232,7 +232,6 @@ static int pwm_sifive_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct pwm_sifive_ddata *ddata; struct pwm_chip *chip; - struct resource *res; int ret; ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); @@ -248,8 +247,7 @@ static int pwm_sifive_probe(struct platform_device *pdev) chip->base = -1; chip->npwm = 4; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ddata->regs = devm_ioremap_resource(dev, res); + ddata->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(ddata->regs)) return PTR_ERR(ddata->regs); From accef074e9d15da654641fd37741ea7b96ade9c3 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 29 Dec 2019 08:06:10 +0000 Subject: [PATCH 31/66] pwm: atmel: Convert to devm_platform_ioremap_resource() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use devm_platform_ioremap_resource() to simplify code. Signed-off-by: Yangtao Li Acked-by: Claudiu Beznea Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 6161e7e3e9ac..5813339b597b 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -401,7 +401,6 @@ MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); static int atmel_pwm_probe(struct platform_device *pdev) { struct atmel_pwm_chip *atmel_pwm; - struct resource *res; int ret; atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); @@ -412,8 +411,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->data = of_device_get_match_data(&pdev->dev); atmel_pwm->updated_pwms = 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res); + atmel_pwm->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(atmel_pwm->base)) return PTR_ERR(atmel_pwm->base); From 168cc32920effa8b85b828fa4cb53f3e3e98f6d4 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 11 Aug 2020 14:24:30 +0800 Subject: [PATCH 32/66] pwm: imx-tpm: Use dev_err_probe() to simplify error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_err_probe() can reduce code size, uniform error handling and record the defer probe reason etc., use it to simplify the code. Signed-off-by: Anson Huang Acked-by: Lee Jones Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx-tpm.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index fcdf6befb838..aaf629bd8c35 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -350,13 +350,9 @@ static int pwm_imx_tpm_probe(struct platform_device *pdev) return PTR_ERR(tpm->base); tpm->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(tpm->clk)) { - ret = PTR_ERR(tpm->clk); - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to get PWM clock: %d\n", ret); - return ret; - } + if (IS_ERR(tpm->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(tpm->clk), + "failed to get PWM clock\n"); ret = clk_prepare_enable(tpm->clk); if (ret) { From d109d74c4cda019653f8f31d3030d8ff28caa994 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 11 Aug 2020 14:24:31 +0800 Subject: [PATCH 33/66] pwm: imx27: Use dev_err_probe() to simplify error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_err_probe() can reduce code size, uniform error handling and record the defer probe reason etc., use it to simplify the code. Signed-off-by: Anson Huang Acked-by: Lee Jones Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx27.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index c50d453552bd..ceaed0378de7 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -315,27 +315,14 @@ static int pwm_imx27_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imx); imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imx->clk_ipg)) { - int ret = PTR_ERR(imx->clk_ipg); - - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "getting ipg clock failed with %d\n", - ret); - return ret; - } + if (IS_ERR(imx->clk_ipg)) + return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg), + "getting ipg clock failed\n"); imx->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(imx->clk_per)) { - int ret = PTR_ERR(imx->clk_per); - - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to get peripheral clock: %d\n", - ret); - - return ret; - } + if (IS_ERR(imx->clk_per)) + return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per), + "failed to get peripheral clock\n"); imx->chip.ops = &pwm_imx27_ops; imx->chip.dev = &pdev->dev; From f1332e9294158d8969a9bf51f01e0d1b3b844f15 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 11 Aug 2020 14:24:32 +0800 Subject: [PATCH 34/66] pwm: imx1: Use dev_err_probe() to simplify error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dev_err_probe() can reduce code size, uniform error handling and record the defer probe reason etc., use it to simplify the code. Signed-off-by: Anson Huang Acked-by: Lee Jones Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx1.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/pwm/pwm-imx1.c b/drivers/pwm/pwm-imx1.c index 1a60bfd7d659..727e0d3e249e 100644 --- a/drivers/pwm/pwm-imx1.c +++ b/drivers/pwm/pwm-imx1.c @@ -144,23 +144,14 @@ static int pwm_imx1_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imx); imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); - if (IS_ERR(imx->clk_ipg)) { - dev_err(&pdev->dev, "getting ipg clock failed with %ld\n", - PTR_ERR(imx->clk_ipg)); - return PTR_ERR(imx->clk_ipg); - } + if (IS_ERR(imx->clk_ipg)) + return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_ipg), + "getting ipg clock failed\n"); imx->clk_per = devm_clk_get(&pdev->dev, "per"); - if (IS_ERR(imx->clk_per)) { - int ret = PTR_ERR(imx->clk_per); - - if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, - "failed to get peripheral clock: %d\n", - ret); - - return ret; - } + if (IS_ERR(imx->clk_per)) + return dev_err_probe(&pdev->dev, PTR_ERR(imx->clk_per), + "failed to get peripheral clock\n"); imx->chip.ops = &pwm_imx1_ops; imx->chip.dev = &pdev->dev; From 2e978a4564b82c0b5e31e23f5e7ea8bb9d6a23f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2020 09:52:14 +0200 Subject: [PATCH 35/66] pwm: ab8500: Add error message if pwmchip_add() fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pwmchip_add() doesn't emit an error message, so add one in the driver. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index fdf3964db4a6..4b6f9e24e11d 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -106,7 +106,7 @@ static int ab8500_pwm_probe(struct platform_device *pdev) err = pwmchip_add(&ab8500->chip); if (err < 0) - return err; + return dev_err_probe(&pdev->dev, err, "Failed to add pwm chip\n"); dev_dbg(&pdev->dev, "pwm probe successful\n"); platform_set_drvdata(pdev, ab8500); From 269effd03f6142df4c74814cfdd5f0b041b30bf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 13 Oct 2020 10:13:21 +0200 Subject: [PATCH 36/66] pwm: zx: Add missing cleanup in error path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit zx_pwm_probe() called clk_prepare_enable() before; this must be undone in the error path. Fixes: 4836193c435c ("pwm: Add ZTE ZX PWM device driver") Signed-off-by: Uwe Kleine-König Acked-by: Shawn Guo Signed-off-by: Thierry Reding --- drivers/pwm/pwm-zx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pwm/pwm-zx.c b/drivers/pwm/pwm-zx.c index 0f5e8919b034..34e91195ce98 100644 --- a/drivers/pwm/pwm-zx.c +++ b/drivers/pwm/pwm-zx.c @@ -236,6 +236,7 @@ static int zx_pwm_probe(struct platform_device *pdev) ret = pwmchip_add(&zpc->chip); if (ret < 0) { dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret); + clk_disable_unprepare(zpc->pclk); return ret; } From 5e5da1e9fbeecdf9d7a7495d7ae2a37453e38499 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 6 Nov 2020 18:15:47 +0100 Subject: [PATCH 37/66] pwm: ab8500: Explicitly allocate pwm chip base dynamically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ab8500 driver is the last one which doesn't (explicitly) use dynamic allocation of the pwm id. Looking through the kernel sources I didn't find a place that relies on this id. And with the device probed from device tree pdev->id is -1 anyhow; making this explicit looks beneficial, too. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-ab8500.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-ab8500.c b/drivers/pwm/pwm-ab8500.c index 4b6f9e24e11d..58c6c0f5b0ec 100644 --- a/drivers/pwm/pwm-ab8500.c +++ b/drivers/pwm/pwm-ab8500.c @@ -101,7 +101,7 @@ static int ab8500_pwm_probe(struct platform_device *pdev) ab8500->chip.dev = &pdev->dev; ab8500->chip.ops = &ab8500_pwm_ops; - ab8500->chip.base = pdev->id; + ab8500->chip.base = -1; ab8500->chip.npwm = 1; err = pwmchip_add(&ab8500->chip); From d58560e6fa4611cee0630ef6e12544269563ca75 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 9 Nov 2020 11:57:24 +0100 Subject: [PATCH 38/66] pwm: lpss: Log error from pwm_lpss_is_updating() if the update bit is still set pwm_lpss_is_updating() does a sanity check which should never fail. If the check does actually fail that is worth logging an error, especially since this means that we will skip making the requested changes to the PWM settings. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 3444c56b4bed..939de93c157b 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -76,7 +76,12 @@ static int pwm_lpss_wait_for_update(struct pwm_device *pwm) static inline int pwm_lpss_is_updating(struct pwm_device *pwm) { - return (pwm_lpss_read(pwm) & PWM_SW_UPDATE) ? -EBUSY : 0; + if (pwm_lpss_read(pwm) & PWM_SW_UPDATE) { + dev_err(pwm->chip->dev, "PWM_SW_UPDATE is still set, skipping update\n"); + return -EBUSY; + } + + return 0; } static void pwm_lpss_prepare(struct pwm_lpss_chip *lpwm, struct pwm_device *pwm, From b9c90f153d836522621b5504087cf83419886e30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 9 Nov 2020 11:57:25 +0100 Subject: [PATCH 39/66] pwm: lpss: Use DPM_FLAG_NO_DIRECT_COMPLETE instead of declaring a prepare handler ACPI LPSS devices use direct-complete style suspend/resume handling by default. We set the DPM_FLAG_SMART_PREPARE and define a prepare handler to disable this on Cherry Trail devices. Clean this up a bit by setting the DPM_FLAG_NO_DIRECT_COMPLETE flag for Cherry Trail devices, instead of defining a prepare handler. While at it also improve the comment explaining why this is necessary. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss-platform.c | 35 ++++++++++++++------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index c6502cf7a7af..ac33861edb48 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -58,7 +58,21 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev) platform_set_drvdata(pdev, lpwm); - dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_SMART_PREPARE); + /* + * On Cherry Trail devices the GFX0._PS0 AML checks if the controller + * is on and if it is not on it turns it on and restores what it + * believes is the correct state to the PWM controller. + * Because of this we must disallow direct-complete, which keeps the + * controller (runtime)suspended on resume, to avoid 2 issues: + * 1. The controller getting turned on without the linux-pm code + * knowing about this. On devices where the controller is unused + * this causes it to stay on during the next suspend causing high + * battery drain (because S0i3 is not reached) + * 2. The state restoring code unexpectedly messing with the controller + */ + if (info->other_devices_aml_touches_pwm_regs) + dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); + pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -73,24 +87,6 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev) return pwm_lpss_remove(lpwm); } -static int pwm_lpss_prepare(struct device *dev) -{ - struct pwm_lpss_chip *lpwm = dev_get_drvdata(dev); - - /* - * If other device's AML code touches the PWM regs on suspend/resume - * force runtime-resume the PWM controller to allow this. - */ - if (lpwm->info->other_devices_aml_touches_pwm_regs) - return 0; /* Force runtime-resume */ - - return 1; /* If runtime-suspended leave as is */ -} - -static const struct dev_pm_ops pwm_lpss_platform_pm_ops = { - .prepare = pwm_lpss_prepare, -}; - static const struct acpi_device_id pwm_lpss_acpi_match[] = { { "80860F09", (unsigned long)&pwm_lpss_byt_info }, { "80862288", (unsigned long)&pwm_lpss_bsw_info }, @@ -104,7 +100,6 @@ static struct platform_driver pwm_lpss_driver_platform = { .driver = { .name = "pwm-lpss", .acpi_match_table = pwm_lpss_acpi_match, - .pm = &pwm_lpss_platform_pm_ops, }, .probe = pwm_lpss_probe_platform, .remove = pwm_lpss_remove_platform, From e3aa45f2f88b6779ab798c63a4deb7ddff949ac7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 9 Nov 2020 11:57:26 +0100 Subject: [PATCH 40/66] pwm: lpss: Set DPM_FLAG_SMART_SUSPEND on Cherry Trail devices As the comment above the code setting the DPM_FLAG_NO_DIRECT_COMPLETE flag explains: /* * On Cherry Trail devices the GFX0._PS0 AML checks if the controller * is on and if it is not on it turns it on and restores what it * believes is the correct state to the PWM controller. * Because of this we must disallow direct-complete, which keeps the * controller (runtime)suspended, on resume to avoid 2 issues: * 1. The controller getting turned on without the linux-pm code * knowing about this. On devices where the controller is unused * this causes it to stay on during the next suspend causing high * battery drain (because S0i3 is not reached) * 2. The state restoring code unexpectedly messing with the controller */ The pm-core must not skip resume to avoid the GFX0._PS0 AML code messing with the PWM controller behind our back. But leaving the controller runtime-suspended (skipping runtime-resume + normal-suspend) during suspend is fine. Set the DPM_FLAG_SMART_SUSPEND flag to allow this. Reviewed-by: Andy Shevchenko Signed-off-by: Hans de Goede Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lpss-platform.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c index ac33861edb48..986786be1e49 100644 --- a/drivers/pwm/pwm-lpss-platform.c +++ b/drivers/pwm/pwm-lpss-platform.c @@ -69,9 +69,13 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev) * this causes it to stay on during the next suspend causing high * battery drain (because S0i3 is not reached) * 2. The state restoring code unexpectedly messing with the controller + * + * Leaving the controller runtime-suspended (skipping runtime-resume + + * normal-suspend) during suspend is fine. */ if (info->other_devices_aml_touches_pwm_regs) - dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NO_DIRECT_COMPLETE); + dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NO_DIRECT_COMPLETE| + DPM_FLAG_SMART_SUSPEND); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); From 44db5363fab8c91292ee6083493f1fd50201ed86 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Fri, 30 Oct 2020 22:12:54 +0200 Subject: [PATCH 41/66] pwm: tiehrpwm: Handle deferred probe with dev_err_probe() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The devm_clk_get() may return -EPROBE_DEFER which is not handled properly by TI EHRPWM driver and causes unnecessary boot log messages. Hence, add proper deferred probe handling with new dev_err_probe() API. Signed-off-by: Grygorii Strashko Reviewed-by: Vignesh Raghavendra Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-tiehrpwm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 97dc62fe9175..a7fb224d6535 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -436,10 +436,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) } } - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get clock\n"); - return PTR_ERR(clk); - } + if (IS_ERR(clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(clk), "Failed to get fck\n"); pc->clk_rate = clk_get_rate(clk); if (!pc->clk_rate) { @@ -460,10 +458,8 @@ static int ehrpwm_pwm_probe(struct platform_device *pdev) /* Acquire tbclk for Time Base EHRPWM submodule */ pc->tbclk = devm_clk_get(&pdev->dev, "tbclk"); - if (IS_ERR(pc->tbclk)) { - dev_err(&pdev->dev, "Failed to get tbclk\n"); - return PTR_ERR(pc->tbclk); - } + if (IS_ERR(pc->tbclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pc->tbclk), "Failed to get tbclk\n"); ret = clk_prepare(pc->tbclk); if (ret < 0) { From cd6720ba022bae39e0b37ec12a3fc810643a779c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 30 Oct 2020 19:36:55 +0100 Subject: [PATCH 42/66] dt-bindings: microchip: atmel,at91rm9200-tcb: Add atmel,tcb-pwm Move the TCB pwm nodes under their parent. This removes the need for the tc-block property as there is now a child-parent relationship between the TC channel and the TC block. Move the documentation to the main file. Signed-off-by: Alexandre Belloni Reviewed-by: Rob Herring Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/atmel-tcb-pwm.txt | 16 --------- .../soc/microchip/atmel,at91rm9200-tcb.yaml | 34 ++++++++++++++++++- 2 files changed, 33 insertions(+), 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt diff --git a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt deleted file mode 100644 index 985fcc65f8c4..000000000000 --- a/Documentation/devicetree/bindings/pwm/atmel-tcb-pwm.txt +++ /dev/null @@ -1,16 +0,0 @@ -Atmel TCB PWM controller - -Required properties: -- compatible: should be "atmel,tcb-pwm" -- #pwm-cells: should be 3. See pwm.yaml in this directory for a description of - the cells format. The only third cell flag supported by this binding is - PWM_POLARITY_INVERTED. -- tc-block: The Timer Counter block to use as a PWM chip. - -Example: - -pwm { - compatible = "atmel,tcb-pwm"; - #pwm-cells = <3>; - tc-block = <1>; -}; diff --git a/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml b/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml index 55fffae05dcf..597d67fba92f 100644 --- a/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml +++ b/Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml @@ -59,6 +59,7 @@ patternProperties: items: - enum: - atmel,tcb-timer + - atmel,tcb-pwm - microchip,tcb-capture reg: description: @@ -68,10 +69,35 @@ patternProperties: minItems: 1 maxItems: 3 + required: + - compatible + - reg + + "^pwm@[0-2]$": + description: The timer block channels that are used as PWMs. + $ref: ../../pwm/pwm.yaml# + type: object + properties: + compatible: + const: atmel,tcb-pwm + reg: + description: + TCB channel to use for this PWM. + enum: [ 0, 1, 2 ] + + "#pwm-cells": + description: + The only third cell flag supported by this binding is + PWM_POLARITY_INVERTED. + const: 3 required: - compatible - reg + - "#pwm-cells" + + additionalProperties: false + allOf: - if: @@ -158,7 +184,13 @@ examples: compatible = "atmel,tcb-timer"; reg = <1>; }; - }; + + pwm@2 { + compatible = "atmel,tcb-pwm"; + reg = <2>; + #pwm-cells = <3>; + }; + }; /* TCB0 Capture with QDEC: */ timer@f800c000 { compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; From 061f8572a31c0da6621aacfc70ed16e1a6d1d33b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 30 Oct 2020 19:36:56 +0100 Subject: [PATCH 43/66] pwm: atmel-tcb: Switch to new binding The PWM is now a subnode of the used TCB. This is cleaner and it mainly allows to stop wasting TCB channels when only 2 or 4 PWMs are used. This also removes the atmel_tclib dependency Cc: Thierry Reding Cc: linux-pwm@vger.kernel.org Signed-off-by: Alexandre Belloni Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 3 +- drivers/pwm/pwm-atmel-tcb.c | 241 ++++++++++++++++++++---------------- 2 files changed, 137 insertions(+), 107 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 63be5362fd3a..ce02d7fe9513 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -75,7 +75,8 @@ config PWM_ATMEL_HLCDC_PWM config PWM_ATMEL_TCB tristate "Atmel TC Block PWM support" - depends on ATMEL_TCLIB && OF + depends on OF + select REGMAP_MMIO help Generic PWM framework driver for Atmel Timer Counter Block. diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 85c53701958c..82edb44fbbd8 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -16,13 +16,16 @@ #include #include #include +#include #include #include #include +#include +#include #include #include -#define NPWM 6 +#define NPWM 2 #define ATMEL_TC_ACMR_MASK (ATMEL_TC_ACPA | ATMEL_TC_ACPC | \ ATMEL_TC_AEEVT | ATMEL_TC_ASWTRG) @@ -48,11 +51,17 @@ struct atmel_tcb_channel { struct atmel_tcb_pwm_chip { struct pwm_chip chip; spinlock_t lock; - struct atmel_tc *tc; + u8 channel; + u8 width; + struct regmap *regmap; + struct clk *clk; + struct clk *slow_clk; struct atmel_tcb_pwm_device *pwms[NPWM]; - struct atmel_tcb_channel bkup[NPWM / 2]; + struct atmel_tcb_channel bkup; }; +const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128, 0, }; + static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip) { return container_of(chip, struct atmel_tcb_pwm_chip, chip); @@ -74,10 +83,6 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm; - struct atmel_tc *tc = tcbpwmc->tc; - void __iomem *regs = tc->regs; - unsigned group = pwm->hwpwm / 2; - unsigned index = pwm->hwpwm % 2; unsigned cmr; int ret; @@ -85,7 +90,7 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, if (!tcbpwm) return -ENOMEM; - ret = clk_prepare_enable(tc->clk[group]); + ret = clk_prepare_enable(tcbpwmc->clk); if (ret) { devm_kfree(chip->dev, tcbpwm); return ret; @@ -98,28 +103,31 @@ static int atmel_tcb_pwm_request(struct pwm_chip *chip, tcbpwm->div = 0; spin_lock(&tcbpwmc->lock); - cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR)); + regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); /* * Get init config from Timer Counter registers if * Timer Counter is already configured as a PWM generator. */ if (cmr & ATMEL_TC_WAVE) { - if (index == 0) - tcbpwm->duty = - __raw_readl(regs + ATMEL_TC_REG(group, RA)); + if (pwm->hwpwm == 0) + regmap_read(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, RA), + &tcbpwm->duty); else - tcbpwm->duty = - __raw_readl(regs + ATMEL_TC_REG(group, RB)); + regmap_read(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, RB), + &tcbpwm->duty); tcbpwm->div = cmr & ATMEL_TC_TCCLKS; - tcbpwm->period = __raw_readl(regs + ATMEL_TC_REG(group, RC)); + regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC), + &tcbpwm->period); cmr &= (ATMEL_TC_TCCLKS | ATMEL_TC_ACMR_MASK | ATMEL_TC_BCMR_MASK); } else cmr = 0; cmr |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0; - __raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR)); + regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); spin_unlock(&tcbpwmc->lock); tcbpwmc->pwms[pwm->hwpwm] = tcbpwm; @@ -131,9 +139,8 @@ static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); - struct atmel_tc *tc = tcbpwmc->tc; - clk_disable_unprepare(tc->clk[pwm->hwpwm / 2]); + clk_disable_unprepare(tcbpwmc->clk); tcbpwmc->pwms[pwm->hwpwm] = NULL; devm_kfree(chip->dev, tcbpwm); } @@ -142,10 +149,6 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); - struct atmel_tc *tc = tcbpwmc->tc; - void __iomem *regs = tc->regs; - unsigned group = pwm->hwpwm / 2; - unsigned index = pwm->hwpwm % 2; unsigned cmr; enum pwm_polarity polarity = tcbpwm->polarity; @@ -161,10 +164,10 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) polarity = !polarity; spin_lock(&tcbpwmc->lock); - cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR)); + regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); /* flush old setting and set the new one */ - if (index == 0) { + if (pwm->hwpwm == 0) { cmr &= ~ATMEL_TC_ACMR_MASK; if (polarity == PWM_POLARITY_INVERSED) cmr |= ATMEL_TC_ASWTRG_CLEAR; @@ -178,20 +181,22 @@ static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) cmr |= ATMEL_TC_BSWTRG_SET; } - __raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR)); + regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); /* * Use software trigger to apply the new setting. * If both PWM devices in this group are disabled we stop the clock. */ if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC))) { - __raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS, - regs + ATMEL_TC_REG(group, CCR)); - tcbpwmc->bkup[group].enabled = 1; + regmap_write(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, CCR), + ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS); + tcbpwmc->bkup.enabled = 1; } else { - __raw_writel(ATMEL_TC_SWTRG, regs + - ATMEL_TC_REG(group, CCR)); - tcbpwmc->bkup[group].enabled = 0; + regmap_write(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, CCR), + ATMEL_TC_SWTRG); + tcbpwmc->bkup.enabled = 0; } spin_unlock(&tcbpwmc->lock); @@ -201,10 +206,6 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); - struct atmel_tc *tc = tcbpwmc->tc; - void __iomem *regs = tc->regs; - unsigned group = pwm->hwpwm / 2; - unsigned index = pwm->hwpwm % 2; u32 cmr; enum pwm_polarity polarity = tcbpwm->polarity; @@ -220,12 +221,12 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) polarity = !polarity; spin_lock(&tcbpwmc->lock); - cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR)); + regmap_read(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), &cmr); /* flush old setting and set the new one */ cmr &= ~ATMEL_TC_TCCLKS; - if (index == 0) { + if (pwm->hwpwm == 0) { cmr &= ~ATMEL_TC_ACMR_MASK; /* Set CMR flags according to given polarity */ @@ -248,7 +249,7 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) * this config till next config call. */ if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) { - if (index == 0) { + if (pwm->hwpwm == 0) { if (polarity == PWM_POLARITY_INVERSED) cmr |= ATMEL_TC_ACPA_SET | ATMEL_TC_ACPC_CLEAR; else @@ -263,19 +264,24 @@ static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) cmr |= (tcbpwm->div & ATMEL_TC_TCCLKS); - __raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR)); + regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CMR), cmr); - if (index == 0) - __raw_writel(tcbpwm->duty, regs + ATMEL_TC_REG(group, RA)); + if (pwm->hwpwm == 0) + regmap_write(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, RA), + tcbpwm->duty); else - __raw_writel(tcbpwm->duty, regs + ATMEL_TC_REG(group, RB)); + regmap_write(tcbpwmc->regmap, + ATMEL_TC_REG(tcbpwmc->channel, RB), + tcbpwm->duty); - __raw_writel(tcbpwm->period, regs + ATMEL_TC_REG(group, RC)); + regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, RC), + tcbpwm->period); /* Use software trigger to apply the new setting */ - __raw_writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, - regs + ATMEL_TC_REG(group, CCR)); - tcbpwmc->bkup[group].enabled = 1; + regmap_write(tcbpwmc->regmap, ATMEL_TC_REG(tcbpwmc->channel, CCR), + ATMEL_TC_SWTRG | ATMEL_TC_CLKEN); + tcbpwmc->bkup.enabled = 1; spin_unlock(&tcbpwmc->lock); return 0; } @@ -285,15 +291,12 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, { struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); - unsigned group = pwm->hwpwm / 2; - unsigned index = pwm->hwpwm % 2; struct atmel_tcb_pwm_device *atcbpwm = NULL; - struct atmel_tc *tc = tcbpwmc->tc; int i; int slowclk = 0; unsigned period; unsigned duty; - unsigned rate = clk_get_rate(tc->clk[group]); + unsigned rate = clk_get_rate(tcbpwmc->clk); unsigned long long min; unsigned long long max; @@ -301,13 +304,13 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * Find best clk divisor: * the smallest divisor which can fulfill the period_ns requirements. */ - for (i = 0; i < 5; ++i) { - if (atmel_tc_divisors[i] == 0) { + for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { + if (atmel_tcb_divisors[i] == 0) { slowclk = i; continue; } - min = div_u64((u64)NSEC_PER_SEC * atmel_tc_divisors[i], rate); - max = min << tc->tcb_config->counter_width; + min = div_u64((u64)NSEC_PER_SEC * atmel_tcb_divisors[i], rate); + max = min << tcbpwmc->width; if (max >= period_ns) break; } @@ -316,11 +319,11 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If none of the divisor are small enough to represent period_ns * take slow clock (32KHz). */ - if (i == 5) { + if (i == ARRAY_SIZE(atmel_tcb_divisors)) { i = slowclk; - rate = clk_get_rate(tc->slow_clk); + rate = clk_get_rate(tcbpwmc->slow_clk); min = div_u64(NSEC_PER_SEC, rate); - max = min << tc->tcb_config->counter_width; + max = min << tcbpwmc->width; /* If period is too big return ERANGE error */ if (max < period_ns) @@ -330,17 +333,13 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, duty = div_u64(duty_ns, min); period = div_u64(period_ns, min); - if (index == 0) - atcbpwm = tcbpwmc->pwms[pwm->hwpwm + 1]; + if (pwm->hwpwm == 0) + atcbpwm = tcbpwmc->pwms[1]; else - atcbpwm = tcbpwmc->pwms[pwm->hwpwm - 1]; + atcbpwm = tcbpwmc->pwms[0]; /* - * PWM devices provided by TCB driver are grouped by 2: - * - group 0: PWM 0 & 1 - * - group 1: PWM 2 & 3 - * - group 2: PWM 4 & 5 - * + * PWM devices provided by the TCB driver are grouped by 2. * PWM devices in a given group must be configured with the * same period_ns. * @@ -376,32 +375,63 @@ static const struct pwm_ops atmel_tcb_pwm_ops = { .owner = THIS_MODULE, }; +static struct atmel_tcb_config tcb_rm9200_config = { + .counter_width = 16, +}; + +static struct atmel_tcb_config tcb_sam9x5_config = { + .counter_width = 32, +}; + +static const struct of_device_id atmel_tcb_of_match[] = { + { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, + { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, + { /* sentinel */ } +}; + static int atmel_tcb_pwm_probe(struct platform_device *pdev) { + const struct of_device_id *match; struct atmel_tcb_pwm_chip *tcbpwm; + const struct atmel_tcb_config *config; struct device_node *np = pdev->dev.of_node; - struct atmel_tc *tc; + struct regmap *regmap; + struct clk *clk; + struct clk *slow_clk; + char clk_name[] = "t0_clk"; int err; - int tcblock; + int channel; - err = of_property_read_u32(np, "tc-block", &tcblock); + err = of_property_read_u32(np, "reg", &channel); if (err < 0) { dev_err(&pdev->dev, - "failed to get Timer Counter Block number from device tree (error: %d)\n", + "failed to get Timer Counter Block channel from device tree (error: %d)\n", err); return err; } - tc = atmel_tc_alloc(tcblock); - if (tc == NULL) { - dev_err(&pdev->dev, "failed to allocate Timer Counter Block\n"); - return -ENOMEM; - } + regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + slow_clk = of_clk_get_by_name(np->parent, "slow_clk"); + if (IS_ERR(slow_clk)) + return PTR_ERR(slow_clk); + + clk_name[1] += channel; + clk = of_clk_get_by_name(np->parent, clk_name); + if (IS_ERR(clk)) + clk = of_clk_get_by_name(np->parent, "t0_clk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + match = of_match_node(atmel_tcb_of_match, np->parent); + config = match->data; tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); if (tcbpwm == NULL) { err = -ENOMEM; - goto err_free_tc; + goto err_slow_clk; } tcbpwm->chip.dev = &pdev->dev; @@ -410,11 +440,15 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) tcbpwm->chip.of_pwm_n_cells = 3; tcbpwm->chip.base = -1; tcbpwm->chip.npwm = NPWM; - tcbpwm->tc = tc; + tcbpwm->channel = channel; + tcbpwm->regmap = regmap; + tcbpwm->clk = clk; + tcbpwm->slow_clk = slow_clk; + tcbpwm->width = config->counter_width; - err = clk_prepare_enable(tc->slow_clk); + err = clk_prepare_enable(slow_clk); if (err) - goto err_free_tc; + goto err_slow_clk; spin_lock_init(&tcbpwm->lock); @@ -427,10 +461,10 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) return 0; err_disable_clk: - clk_disable_unprepare(tcbpwm->tc->slow_clk); + clk_disable_unprepare(tcbpwm->slow_clk); -err_free_tc: - atmel_tc_free(tc); +err_slow_clk: + clk_put(slow_clk); return err; } @@ -440,14 +474,14 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev) struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev); int err; - clk_disable_unprepare(tcbpwm->tc->slow_clk); + clk_disable_unprepare(tcbpwm->slow_clk); + clk_put(tcbpwm->slow_clk); + clk_put(tcbpwm->clk); err = pwmchip_remove(&tcbpwm->chip); if (err < 0) return err; - atmel_tc_free(tcbpwm->tc); - return 0; } @@ -461,38 +495,33 @@ MODULE_DEVICE_TABLE(of, atmel_tcb_pwm_dt_ids); static int atmel_tcb_pwm_suspend(struct device *dev) { struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev); - void __iomem *base = tcbpwm->tc->regs; - int i; + struct atmel_tcb_channel *chan = &tcbpwm->bkup; + unsigned int channel = tcbpwm->channel; - for (i = 0; i < (NPWM / 2); i++) { - struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; + regmap_read(tcbpwm->regmap, ATMEL_TC_REG(channel, CMR), &chan->cmr); + regmap_read(tcbpwm->regmap, ATMEL_TC_REG(channel, RA), &chan->ra); + regmap_read(tcbpwm->regmap, ATMEL_TC_REG(channel, RB), &chan->rb); + regmap_read(tcbpwm->regmap, ATMEL_TC_REG(channel, RC), &chan->rc); - chan->cmr = readl(base + ATMEL_TC_REG(i, CMR)); - chan->ra = readl(base + ATMEL_TC_REG(i, RA)); - chan->rb = readl(base + ATMEL_TC_REG(i, RB)); - chan->rc = readl(base + ATMEL_TC_REG(i, RC)); - } return 0; } static int atmel_tcb_pwm_resume(struct device *dev) { struct atmel_tcb_pwm_chip *tcbpwm = dev_get_drvdata(dev); - void __iomem *base = tcbpwm->tc->regs; - int i; + struct atmel_tcb_channel *chan = &tcbpwm->bkup; + unsigned int channel = tcbpwm->channel; - for (i = 0; i < (NPWM / 2); i++) { - struct atmel_tcb_channel *chan = &tcbpwm->bkup[i]; + regmap_write(tcbpwm->regmap, ATMEL_TC_REG(channel, CMR), chan->cmr); + regmap_write(tcbpwm->regmap, ATMEL_TC_REG(channel, RA), chan->ra); + regmap_write(tcbpwm->regmap, ATMEL_TC_REG(channel, RB), chan->rb); + regmap_write(tcbpwm->regmap, ATMEL_TC_REG(channel, RC), chan->rc); + + if (chan->enabled) + regmap_write(tcbpwm->regmap, + ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, + ATMEL_TC_REG(channel, CCR)); - writel(chan->cmr, base + ATMEL_TC_REG(i, CMR)); - writel(chan->ra, base + ATMEL_TC_REG(i, RA)); - writel(chan->rb, base + ATMEL_TC_REG(i, RB)); - writel(chan->rc, base + ATMEL_TC_REG(i, RC)); - if (chan->enabled) { - writel(ATMEL_TC_CLKEN | ATMEL_TC_SWTRG, - base + ATMEL_TC_REG(i, CCR)); - } - } return 0; } #endif From 34cbcd72588f40e58d7db5aa8c125068dd735765 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 30 Oct 2020 19:36:57 +0100 Subject: [PATCH 44/66] pwm: atmel-tcb: Add sama5d2 support Add sama5d2 support. The sama5d2 has a new clock input, its gclk. Index 0 of the clock selector is the gclk instead of the peripheral clock divided by 2. For now, the gclk is not used because the peripheral clock divided by 8 already gives a 9.6ns resolution which is enough for most use cases. Signed-off-by: Alexandre Belloni Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-tcb.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index 82edb44fbbd8..5ccc3e7420e9 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -55,6 +55,7 @@ struct atmel_tcb_pwm_chip { u8 width; struct regmap *regmap; struct clk *clk; + struct clk *gclk; struct clk *slow_clk; struct atmel_tcb_pwm_device *pwms[NPWM]; struct atmel_tcb_channel bkup; @@ -292,7 +293,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); struct atmel_tcb_pwm_device *atcbpwm = NULL; - int i; + int i = 0; int slowclk = 0; unsigned period; unsigned duty; @@ -303,8 +304,11 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * Find best clk divisor: * the smallest divisor which can fulfill the period_ns requirements. + * If there is a gclk, the first divisor is actuallly the gclk selector */ - for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { + if (tcbpwmc->gclk) + i = 1; + for (; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { if (atmel_tcb_divisors[i] == 0) { slowclk = i; continue; @@ -383,9 +387,15 @@ static struct atmel_tcb_config tcb_sam9x5_config = { .counter_width = 32, }; +static struct atmel_tcb_config tcb_sama5d2_config = { + .counter_width = 32, + .has_gclk = 1, +}; + static const struct of_device_id atmel_tcb_of_match[] = { { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, + { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, }, { /* sentinel */ } }; @@ -396,7 +406,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) const struct atmel_tcb_config *config; struct device_node *np = pdev->dev.of_node; struct regmap *regmap; - struct clk *clk; + struct clk *clk, *gclk = NULL; struct clk *slow_clk; char clk_name[] = "t0_clk"; int err; @@ -428,6 +438,12 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) match = of_match_node(atmel_tcb_of_match, np->parent); config = match->data; + if (config->has_gclk) { + gclk = of_clk_get_by_name(np->parent, "gclk"); + if (IS_ERR(gclk)) + return PTR_ERR(gclk); + } + tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); if (tcbpwm == NULL) { err = -ENOMEM; @@ -443,6 +459,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) tcbpwm->channel = channel; tcbpwm->regmap = regmap; tcbpwm->clk = clk; + tcbpwm->gclk = gclk; tcbpwm->slow_clk = slow_clk; tcbpwm->width = config->counter_width; From 1f0f1e80fdd3aa9631f6c22cda4f8550cfcfcc3e Mon Sep 17 00:00:00 2001 From: Lokesh Vutla Date: Fri, 30 Oct 2020 19:11:35 +0530 Subject: [PATCH 45/66] pwm: lp3943: Dynamically allocate PWM chip base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there are other PWM controllers enabled along with pwm-lp3943, pwm-lp3942 is failing to probe with -EEXIST error. This is because other PWM controllers are probed first and assigned PWM base 0 and pwm-lp3943 is requesting for 0 again. In order to avoid this, assign the chip base with -1, so that it is dynamically allocated. Fixes: af66b3c0934e ("pwm: Add LP3943 PWM driver") Signed-off-by: Lokesh Vutla Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-lp3943.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 7551253ada32..bf3f14fb5f24 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -275,6 +275,7 @@ static int lp3943_pwm_probe(struct platform_device *pdev) lp3943_pwm->chip.dev = &pdev->dev; lp3943_pwm->chip.ops = &lp3943_pwm_ops; lp3943_pwm->chip.npwm = LP3943_NUM_PWMS; + lp3943_pwm->chip.base = -1; platform_set_drvdata(pdev, lp3943_pwm); From cb55d17ea2ecb7698bc37e5658b4642eef45a327 Mon Sep 17 00:00:00 2001 From: Vijayakannan Ayyathurai Date: Thu, 22 Oct 2020 15:14:47 +0800 Subject: [PATCH 46/66] dt-bindings: pwm: keembay: Add bindings for Intel Keem Bay PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add PWM Device Tree bindings documentation for the Intel Keem Bay SoC. Signed-off-by: Vineetha G. Jaya Kumaran Reviewed-by: Rob Herring Acked-by: Uwe Kleine-König Signed-off-by: Vijayakannan Ayyathurai Signed-off-by: Thierry Reding --- .../bindings/pwm/intel,keembay-pwm.yaml | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml b/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml new file mode 100644 index 000000000000..ff6880a02ce6 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/intel,keembay-pwm.yaml @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (C) 2020 Intel Corporation +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/pwm/intel,keembay-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel Keem Bay PWM Device Tree Bindings + +maintainers: + - Vijayakannan Ayyathurai + +allOf: + - $ref: pwm.yaml# + +properties: + compatible: + enum: + - intel,keembay-pwm + + reg: + maxItems: 1 + + clocks: + maxItems: 1 + + "#pwm-cells": + const: 2 + +required: + - compatible + - reg + - clocks + - '#pwm-cells' + +additionalProperties: false + +examples: + - | + #define KEEM_BAY_A53_GPIO + + pwm@203200a0 { + compatible = "intel,keembay-pwm"; + reg = <0x203200a0 0xe8>; + clocks = <&scmi_clk KEEM_BAY_A53_GPIO>; + #pwm-cells = <2>; + }; From bd899ceb8f9129cb0d58115447ac9ff8ea907135 Mon Sep 17 00:00:00 2001 From: Vijayakannan Ayyathurai Date: Thu, 22 Oct 2020 15:14:46 +0800 Subject: [PATCH 47/66] pwm: Add PWM driver for Intel Keem Bay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Intel Keem Bay SoC requires PWM support. Add the pwm-keembay driver to enable this. Signed-off-by: Lai, Poey Seng Co-developed-by: Vineetha G. Jaya Kumaran Signed-off-by: Vineetha G. Jaya Kumaran Reviewed-by: Andy Shevchenko Co-developed-by: Vijayakannan Ayyathurai Signed-off-by: Vijayakannan Ayyathurai Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-keembay.c | 240 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 drivers/pwm/pwm-keembay.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ce02d7fe9513..e019db18b6ca 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -255,6 +255,15 @@ config PWM_JZ4740 To compile this driver as a module, choose M here: the module will be called pwm-jz4740. +config PWM_KEEMBAY + tristate "Intel Keem Bay PWM driver" + depends on ARCH_KEEMBAY || (ARM64 && COMPILE_TEST) + help + The platform driver for Intel Keem Bay PWM controller. + + To compile this driver as a module, choose M here: the module + will be called pwm-keembay. + config PWM_LP3943 tristate "TI/National Semiconductor LP3943 PWM support" depends on MFD_LP3943 diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index cbdcd55d69ee..3339f382986d 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_PWM_IMX27) += pwm-imx27.o obj-$(CONFIG_PWM_IMX_TPM) += pwm-imx-tpm.o obj-$(CONFIG_PWM_IQS620A) += pwm-iqs620a.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o +obj-$(CONFIG_PWM_KEEMBAY) += pwm-keembay.o obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c new file mode 100644 index 000000000000..2b6dd070daa4 --- /dev/null +++ b/drivers/pwm/pwm-keembay.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Keem Bay PWM driver + * + * Copyright (C) 2020 Intel Corporation + * Authors: Lai Poey Seng + * Vineetha G. Jaya Kumaran + * + * Limitations: + * - Upon disabling a channel, the currently running + * period will not be completed. However, upon + * reconfiguration of the duty cycle/period, the + * currently running period will be completed first. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define KMB_TOTAL_PWM_CHANNELS 6 +#define KMB_PWM_COUNT_MAX U16_MAX +#define KMB_PWM_EN_BIT BIT(31) + +/* Mask */ +#define KMB_PWM_HIGH_MASK GENMASK(31, 16) +#define KMB_PWM_LOW_MASK GENMASK(15, 0) +#define KMB_PWM_LEADIN_MASK GENMASK(30, 0) + +/* PWM Register offset */ +#define KMB_PWM_LEADIN_OFFSET(ch) (0x00 + 4 * (ch)) +#define KMB_PWM_HIGHLOW_OFFSET(ch) (0x20 + 4 * (ch)) + +struct keembay_pwm { + struct pwm_chip chip; + struct device *dev; + struct clk *clk; + void __iomem *base; +}; + +static inline struct keembay_pwm *to_keembay_pwm_dev(struct pwm_chip *chip) +{ + return container_of(chip, struct keembay_pwm, chip); +} + +static void keembay_clk_unprepare(void *data) +{ + clk_disable_unprepare(data); +} + +static int keembay_clk_enable(struct device *dev, struct clk *clk) +{ + int ret; + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, keembay_clk_unprepare, clk); +} + +static inline void keembay_pwm_update_bits(struct keembay_pwm *priv, u32 mask, + u32 val, u32 offset) +{ + u32 buff = readl(priv->base + offset); + + buff = u32_replace_bits(buff, val, mask); + writel(buff, priv->base + offset); +} + +static void keembay_pwm_enable(struct keembay_pwm *priv, int ch) +{ + keembay_pwm_update_bits(priv, KMB_PWM_EN_BIT, 1, + KMB_PWM_LEADIN_OFFSET(ch)); +} + +static void keembay_pwm_disable(struct keembay_pwm *priv, int ch) +{ + keembay_pwm_update_bits(priv, KMB_PWM_EN_BIT, 0, + KMB_PWM_LEADIN_OFFSET(ch)); +} + +static void keembay_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct keembay_pwm *priv = to_keembay_pwm_dev(chip); + unsigned long long high, low; + unsigned long clk_rate; + u32 highlow; + + clk_rate = clk_get_rate(priv->clk); + + /* Read channel enabled status */ + highlow = readl(priv->base + KMB_PWM_LEADIN_OFFSET(pwm->hwpwm)); + if (highlow & KMB_PWM_EN_BIT) + state->enabled = true; + else + state->enabled = false; + + /* Read period and duty cycle */ + highlow = readl(priv->base + KMB_PWM_HIGHLOW_OFFSET(pwm->hwpwm)); + low = FIELD_GET(KMB_PWM_LOW_MASK, highlow) * NSEC_PER_SEC; + high = FIELD_GET(KMB_PWM_HIGH_MASK, highlow) * NSEC_PER_SEC; + state->duty_cycle = DIV_ROUND_UP_ULL(high, clk_rate); + state->period = DIV_ROUND_UP_ULL(high + low, clk_rate); + state->polarity = PWM_POLARITY_NORMAL; +} + +static int keembay_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct keembay_pwm *priv = to_keembay_pwm_dev(chip); + struct pwm_state current_state; + unsigned long long div; + unsigned long clk_rate; + u32 pwm_count = 0; + u16 high, low; + + if (state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + /* + * Configure the pwm repeat count as infinite at (15:0) and leadin + * low time as 0 at (30:16), which is in terms of clock cycles. + */ + keembay_pwm_update_bits(priv, KMB_PWM_LEADIN_MASK, 0, + KMB_PWM_LEADIN_OFFSET(pwm->hwpwm)); + + keembay_pwm_get_state(chip, pwm, ¤t_state); + + if (!state->enabled) { + if (current_state.enabled) + keembay_pwm_disable(priv, pwm->hwpwm); + return 0; + } + + /* + * The upper 16 bits and lower 16 bits of the KMB_PWM_HIGHLOW_OFFSET + * register contain the high time and low time of waveform accordingly. + * All the values are in terms of clock cycles. + */ + + clk_rate = clk_get_rate(priv->clk); + div = clk_rate * state->duty_cycle; + div = DIV_ROUND_DOWN_ULL(div, NSEC_PER_SEC); + if (div > KMB_PWM_COUNT_MAX) + return -ERANGE; + + high = div; + div = clk_rate * state->period; + div = DIV_ROUND_DOWN_ULL(div, NSEC_PER_SEC); + div = div - high; + if (div > KMB_PWM_COUNT_MAX) + return -ERANGE; + + low = div; + + pwm_count = FIELD_PREP(KMB_PWM_HIGH_MASK, high) | + FIELD_PREP(KMB_PWM_LOW_MASK, low); + + writel(pwm_count, priv->base + KMB_PWM_HIGHLOW_OFFSET(pwm->hwpwm)); + + if (state->enabled && !current_state.enabled) + keembay_pwm_enable(priv, pwm->hwpwm); + + return 0; +} + +static const struct pwm_ops keembay_pwm_ops = { + .owner = THIS_MODULE, + .apply = keembay_pwm_apply, + .get_state = keembay_pwm_get_state, +}; + +static int keembay_pwm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct keembay_pwm *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clock\n"); + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + ret = keembay_clk_enable(dev, priv->clk); + if (ret) + return ret; + + priv->chip.base = -1; + priv->chip.dev = dev; + priv->chip.ops = &keembay_pwm_ops; + priv->chip.npwm = KMB_TOTAL_PWM_CHANNELS; + + ret = pwmchip_add(&priv->chip); + if (ret) + return dev_err_probe(dev, ret, "Failed to add PWM chip\n"); + + platform_set_drvdata(pdev, priv); + + return 0; +} + +static int keembay_pwm_remove(struct platform_device *pdev) +{ + struct keembay_pwm *priv = platform_get_drvdata(pdev); + + return pwmchip_remove(&priv->chip); +} + +static const struct of_device_id keembay_pwm_of_match[] = { + { .compatible = "intel,keembay-pwm" }, + { } +}; +MODULE_DEVICE_TABLE(of, keembay_pwm_of_match); + +static struct platform_driver keembay_pwm_driver = { + .probe = keembay_pwm_probe, + .remove = keembay_pwm_remove, + .driver = { + .name = "pwm-keembay", + .of_match_table = keembay_pwm_of_match, + }, +}; +module_platform_driver(keembay_pwm_driver); + +MODULE_ALIAS("platform:pwm-keembay"); +MODULE_DESCRIPTION("Intel Keem Bay PWM driver"); +MODULE_LICENSE("GPL v2"); From ad5a228b9bad44e2a652e45fd9ac767d8880f480 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 19 Oct 2020 16:07:01 +0200 Subject: [PATCH 48/66] dt-bindings: pwm: pwm-mediatek: Add documentation for MT8183 SoC Add binding documentation for the MT8183 SoC. Signed-off-by: Fabien Parent Reviewed-by: Matthias Brugger Acked-by: Rob Herring Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/pwm-mediatek.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt b/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt index 29adff59c479..25ed214473d7 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-mediatek.txt @@ -7,6 +7,7 @@ Required properties: - "mediatek,mt7623-pwm": found on mt7623 SoC. - "mediatek,mt7628-pwm": found on mt7628 SoC. - "mediatek,mt7629-pwm": found on mt7629 SoC. + - "mediatek,mt8183-pwm": found on mt8183 SoC. - "mediatek,mt8516-pwm": found on mt8516 SoC. - reg: physical base address and length of the controller's registers. - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of From 0c0ead76235db0bcfaab83f04db546995449d002 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 19 Oct 2020 16:07:02 +0200 Subject: [PATCH 49/66] pwm: mediatek: Always use bus clock The MediaTek PWM IP can sometimes use the 26 MHz source clock to generate the PWM signal, but the driver currently assumes that we always use the PWM bus clock to generate the PWM signal. This commit modifies the PWM driver in order to force the PWM IP to always use the bus clock as source clock. I do not have the datasheet of all the MediaTek SoC, so I don't know if the register to choose the source clock is present in all the SoCs or only in subset. As a consequence I made this change optional by using a platform data paremeter to says whether this register is supported or not. On all the SoCs I don't have the datasheet (MT2712, MT7622, MT7623, MT7628, MT7629) I kept the behavior to be the same as before this change. Signed-off-by: Fabien Parent Reviewed-by: Matthias Brugger Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6bc851cadb3e..ad3770bfc202 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -30,12 +30,14 @@ #define PWM45DWIDTH_FIXUP 0x30 #define PWMTHRES 0x30 #define PWM45THRES_FIXUP 0x34 +#define PWM_CK_26M_SEL 0x210 #define PWM_CLK_DIV_MAX 7 struct pwm_mediatek_of_data { unsigned int num_pwms; bool pwm45_fixup; + bool has_ck_26m_sel; }; /** @@ -132,6 +134,10 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, if (ret < 0) return ret; + /* Make sure we use the bus clock and not the 26MHz clock */ + if (pc->soc->has_ck_26m_sel) + writel(0, pc->regs + PWM_CK_26M_SEL); + /* Using resolution in picosecond gets accuracy higher */ resolution = (u64)NSEC_PER_SEC * 1000; do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm])); @@ -279,31 +285,37 @@ static int pwm_mediatek_remove(struct platform_device *pdev) static const struct pwm_mediatek_of_data mt2712_pwm_data = { .num_pwms = 8, .pwm45_fixup = false, + .has_ck_26m_sel = false, }; static const struct pwm_mediatek_of_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, + .has_ck_26m_sel = false, }; static const struct pwm_mediatek_of_data mt7623_pwm_data = { .num_pwms = 5, .pwm45_fixup = true, + .has_ck_26m_sel = false, }; static const struct pwm_mediatek_of_data mt7628_pwm_data = { .num_pwms = 4, .pwm45_fixup = true, + .has_ck_26m_sel = false, }; static const struct pwm_mediatek_of_data mt7629_pwm_data = { .num_pwms = 1, .pwm45_fixup = false, + .has_ck_26m_sel = false, }; static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, + .has_ck_26m_sel = true, }; static const struct of_device_id pwm_mediatek_of_match[] = { From 8b2fbaed90f6291a221d02c31e16a1ce722f79fc Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 19 Oct 2020 16:07:03 +0200 Subject: [PATCH 50/66] pwm: mediatek: Add MT8183 SoC support Add PWM support for the MT8183 SoC. Signed-off-by: Fabien Parent Reviewed-by: Matthias Brugger Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index ad3770bfc202..fcfc3b147e5f 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -312,6 +312,12 @@ static const struct pwm_mediatek_of_data mt7629_pwm_data = { .has_ck_26m_sel = false, }; +static const struct pwm_mediatek_of_data mt8183_pwm_data = { + .num_pwms = 4, + .pwm45_fixup = false, + .has_ck_26m_sel = true, +}; + static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, @@ -324,6 +330,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = { { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, { .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data }, + { .compatible = "mediatek,mt8183-pwm", .data = &mt8183_pwm_data }, { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, { }, }; From 554b3b31e9229b498dc17f9bc0f14b42c586f0e9 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Fri, 16 Oct 2020 20:50:15 +0200 Subject: [PATCH 51/66] dt-bindings: pwm: mtk-disp: add MT8167 SoC binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add binding for MT8167 SoC. The IP is compatible with MT8173. Signed-off-by: Fabien Parent Acked-by: Uwe Kleine-König Acked-by: Rob Herring Signed-off-by: Thierry Reding --- Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt index 0521957c253f..902b271891ae 100644 --- a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt +++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt @@ -4,6 +4,7 @@ Required properties: - compatible: should be "mediatek,-disp-pwm": - "mediatek,mt2701-disp-pwm": found on mt2701 SoC. - "mediatek,mt6595-disp-pwm": found on mt6595 SoC. + - "mediatek,mt8167-disp-pwm", "mediatek,mt8173-disp-pwm": found on mt8167 SoC. - "mediatek,mt8173-disp-pwm": found on mt8173 SoC. - reg: physical base address and length of the controller's registers. - #pwm-cells: must be 2. See pwm.yaml in this directory for a description of From 1ed2b3fca64516d1b3503ef21929f3b5f4f41cc6 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 2 Oct 2020 16:56:13 +0300 Subject: [PATCH 52/66] pwm: Add DesignWare PWM Controller Driver Introduce driver for Synopsys DesignWare PWM Controller used on Intel Elkhart Lake. Initial implementation is done by Felipe Balbi while he was working at Intel with later changes from Raymond Tan and me. Co-developed-by: Felipe Balbi (Intel) Signed-off-by: Felipe Balbi (Intel) Co-developed-by: Raymond Tan Signed-off-by: Raymond Tan Signed-off-by: Jarkko Nikula Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-dwc.c | 319 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 drivers/pwm/pwm-dwc.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index e019db18b6ca..d2c199b93585 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -161,6 +161,15 @@ config PWM_CROS_EC PWM driver for exposing a PWM attached to the ChromeOS Embedded Controller. +config PWM_DWC + tristate "DesignWare PWM Controller" + depends on 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. + 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 3339f382986d..2dd881665698 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o 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_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.c b/drivers/pwm/pwm-dwc.c new file mode 100644 index 000000000000..f6c98e0d57c2 --- /dev/null +++ b/drivers/pwm/pwm-dwc.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DesignWare PWM Controller driver + * + * Copyright (C) 2018-2020 Intel Corporation + * + * Author: Felipe Balbi (Intel) + * Author: Jarkko Nikula + * Author: Raymond Tan + * + * 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 +#include +#include +#include +#include +#include +#include + +#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); +} + +static void __dwc_pwm_set_enable(struct dwc_pwm *dwc, int pwm, int enabled) +{ + u32 reg; + + reg = dwc_pwm_readl(dwc, DWC_TIM_CTRL(pwm)); + + if (enabled) + reg |= DWC_TIM_CTRL_EN; + else + reg &= ~DWC_TIM_CTRL_EN; + + dwc_pwm_writel(dwc, reg, DWC_TIM_CTRL(pwm)); +} + +static int __dwc_pwm_configure_timer(struct dwc_pwm *dwc, + struct pwm_device *pwm, + const struct pwm_state *state) +{ + u64 tmp; + u32 ctrl; + u32 high; + u32 low; + + /* + * Calculate width of low and high period in terms of input clock + * periods and check are the result within HW limits between 1 and + * 2^32 periods. + */ + tmp = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + low = tmp - 1; + + tmp = DIV_ROUND_CLOSEST_ULL(state->period - state->duty_cycle, + DWC_CLK_PERIOD_NS); + if (tmp < 1 || tmp > (1ULL << 32)) + return -ERANGE; + high = tmp - 1; + + /* + * Specification says timer usage flow is to disable timer, then + * program it followed by enable. It also says Load Count is loaded + * into timer after it is enabled - either after a disable or + * a reset. Based on measurements it happens also without disable + * whenever Load Count is updated. But follow the specification. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + + /* + * Write Load Count and Load Count 2 registers. Former defines the + * width of low period and latter the width of high period in terms + * multiple of input clock periods: + * Width = ((Count + 1) * input clock period). + */ + dwc_pwm_writel(dwc, low, DWC_TIM_LD_CNT(pwm->hwpwm)); + dwc_pwm_writel(dwc, high, DWC_TIM_LD_CNT2(pwm->hwpwm)); + + /* + * Set user-defined mode, timer reloads from Load Count registers + * when it counts down to 0. + * Set PWM mode, it makes output to toggle and width of low and high + * periods are set by Load Count registers. + */ + ctrl = DWC_TIM_CTRL_MODE_USER | DWC_TIM_CTRL_PWM; + dwc_pwm_writel(dwc, ctrl, DWC_TIM_CTRL(pwm->hwpwm)); + + /* + * Enable timer. Output starts from low period. + */ + __dwc_pwm_set_enable(dwc, pwm->hwpwm, state->enabled); + + return 0; +} + +static int dwc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + + if (state->polarity != PWM_POLARITY_INVERSED) + return -EINVAL; + + if (state->enabled) { + if (!pwm->state.enabled) + pm_runtime_get_sync(chip->dev); + return __dwc_pwm_configure_timer(dwc, pwm, state); + } else { + if (pwm->state.enabled) { + __dwc_pwm_set_enable(dwc, pwm->hwpwm, false); + pm_runtime_put_sync(chip->dev); + } + } + + return 0; +} + +static void dwc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct dwc_pwm *dwc = to_dwc_pwm(chip); + u64 duty, period; + + pm_runtime_get_sync(chip->dev); + + state->enabled = !!(dwc_pwm_readl(dwc, + DWC_TIM_CTRL(pwm->hwpwm)) & DWC_TIM_CTRL_EN); + + duty = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT(pwm->hwpwm)); + duty += 1; + duty *= DWC_CLK_PERIOD_NS; + state->duty_cycle = duty; + + period = dwc_pwm_readl(dwc, DWC_TIM_LD_CNT2(pwm->hwpwm)); + period += 1; + period *= DWC_CLK_PERIOD_NS; + period += duty; + state->period = period; + + state->polarity = PWM_POLARITY_INVERSED; + + pm_runtime_put_sync(chip->dev); +} + +static const struct pwm_ops dwc_pwm_ops = { + .apply = dwc_pwm_apply, + .get_state = dwc_pwm_get_state, + .owner = THIS_MODULE, +}; + +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 = devm_kzalloc(&pci->dev, sizeof(*dwc), GFP_KERNEL); + if (!dwc) + return -ENOMEM; + + ret = pcim_enable_device(pci); + if (ret) { + dev_err(&pci->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(&pci->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(&pci->dev, "Base address missing\n"); + return -ENOMEM; + } + + pci_set_drvdata(pci, dwc); + + dwc->chip.dev = dev; + dwc->chip.ops = &dwc_pwm_ops; + dwc->chip.npwm = DWC_TIMERS_TOTAL; + dwc->chip.base = -1; + + ret = pwmchip_add(&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) +{ + struct dwc_pwm *dwc = pci_get_drvdata(pci); + + pm_runtime_forbid(&pci->dev); + pm_runtime_get_noresume(&pci->dev); + + pwmchip_remove(&dwc->chip); +} + +#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 "); +MODULE_AUTHOR("Raymond Tan "); +MODULE_DESCRIPTION("DesignWare PWM Controller"); +MODULE_LICENSE("GPL"); From 7c0e4f2ef782a4da2126a9399316b689d4fbc013 Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Thu, 5 Nov 2020 13:49:39 +0800 Subject: [PATCH 53/66] Add DT bindings YAML schema for PWM fan controller of LGM SoC Intel's LGM(Lightning Mountain) SoC contains a PWM fan controller which is only used to control the fan attached to the system. This PWM controller does not have any other consumer other than fan. Add DT bindings documentation for this PWM fan controller. Signed-off-by: Rahul Tanwar Reviewed-by: Rob Herring Signed-off-by: Thierry Reding --- .../bindings/pwm/intel,lgm-pwm.yaml | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml diff --git a/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml b/Documentation/devicetree/bindings/pwm/intel,lgm-pwm.yaml new file mode 100644 index 000000000000..11a606536169 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/intel,lgm-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/intel,lgm-pwm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: LGM SoC PWM fan controller + +maintainers: + - Rahul Tanwar + +properties: + compatible: + const: intel,lgm-pwm + + reg: + maxItems: 1 + + "#pwm-cells": + const: 2 + + clocks: + maxItems: 1 + + resets: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - resets + +additionalProperties: false + +examples: + - | + pwm: pwm@e0d00000 { + compatible = "intel,lgm-pwm"; + reg = <0xe0d00000 0x30>; + #pwm-cells = <2>; + clocks = <&cgu0 126>; + resets = <&rcu0 0x30 21>; + }; From 97960addcd9f5a11acd6ab28ebb33d0fde8c14a3 Mon Sep 17 00:00:00 2001 From: Rahul Tanwar Date: Thu, 5 Nov 2020 13:49:40 +0800 Subject: [PATCH 54/66] pwm: Add PWM fan controller driver for LGM SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Intel Lightning Mountain(LGM) SoC contains a PWM fan controller. This PWM controller does not have any other consumer, it is a dedicated PWM controller for fan attached to the system. Add driver for this PWM fan controller. Signed-off-by: Rahul Tanwar Reviewed-by: Andy Shevchenko Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 11 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-intel-lgm.c | 244 ++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 drivers/pwm/pwm-intel-lgm.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index d2c199b93585..b2a87fd7e8fb 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -242,6 +242,17 @@ config PWM_IMX_TPM To compile this driver as a module, choose M here: the module will be called pwm-imx-tpm. +config PWM_INTEL_LGM + tristate "Intel LGM PWM support" + depends on HAS_IOMEM + depends on (OF && X86) || COMPILE_TEST + select REGMAP_MMIO + help + Generic PWM fan controller driver for LGM SoC. + + To compile this driver as a module, choose M here: the module + will be called pwm-intel-lgm. + config PWM_IQS620A tristate "Azoteq IQS620A PWM support" depends on MFD_IQS62X || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 2dd881665698..18b89d7fd092 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o obj-$(CONFIG_PWM_IMX1) += pwm-imx1.o obj-$(CONFIG_PWM_IMX27) += pwm-imx27.o obj-$(CONFIG_PWM_IMX_TPM) += pwm-imx-tpm.o +obj-$(CONFIG_PWM_INTEL_LGM) += pwm-intel-lgm.o obj-$(CONFIG_PWM_IQS620A) += pwm-iqs620a.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o obj-$(CONFIG_PWM_KEEMBAY) += pwm-keembay.o diff --git a/drivers/pwm/pwm-intel-lgm.c b/drivers/pwm/pwm-intel-lgm.c new file mode 100644 index 000000000000..e9e54dda07aa --- /dev/null +++ b/drivers/pwm/pwm-intel-lgm.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Intel Corporation. + * + * Limitations: + * - The hardware supports fixed period & configures only 2-wire mode. + * - Supports normal polarity. Does not support changing polarity. + * - When PWM is disabled, output of PWM will become 0(inactive). It doesn't + * keep track of running period. + * - When duty cycle is changed, PWM output may be a mix of previous setting + * and new setting for the first period. From second period, the output is + * based on new setting. + * - It is a dedicated PWM fan controller. There are no other consumers for + * this PWM controller. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define LGM_PWM_FAN_CON0 0x0 +#define LGM_PWM_FAN_EN_EN BIT(0) +#define LGM_PWM_FAN_EN_DIS 0x0 +#define LGM_PWM_FAN_EN_MSK BIT(0) +#define LGM_PWM_FAN_MODE_2WIRE 0x0 +#define LGM_PWM_FAN_MODE_MSK BIT(1) +#define LGM_PWM_FAN_DC_MSK GENMASK(23, 16) + +#define LGM_PWM_FAN_CON1 0x4 +#define LGM_PWM_FAN_MAX_RPM_MSK GENMASK(15, 0) + +#define LGM_PWM_MAX_RPM (BIT(16) - 1) +#define LGM_PWM_DEFAULT_RPM 4000 +#define LGM_PWM_MAX_DUTY_CYCLE (BIT(8) - 1) + +#define LGM_PWM_DC_BITS 8 + +#define LGM_PWM_PERIOD_2WIRE_NS (40 * NSEC_PER_MSEC) + +struct lgm_pwm_chip { + struct pwm_chip chip; + struct regmap *regmap; + u32 period; +}; + +static inline struct lgm_pwm_chip *to_lgm_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct lgm_pwm_chip, chip); +} + +static int lgm_pwm_enable(struct pwm_chip *chip, bool enable) +{ + struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip); + struct regmap *regmap = pc->regmap; + + return regmap_update_bits(regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_EN_MSK, + enable ? LGM_PWM_FAN_EN_EN : LGM_PWM_FAN_EN_DIS); +} + +static int lgm_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip); + u32 duty_cycle, val; + int ret; + + /* The hardware only supports normal polarity and fixed period. */ + if (state->polarity != PWM_POLARITY_NORMAL || state->period < pc->period) + return -EINVAL; + + if (!state->enabled) + return lgm_pwm_enable(chip, 0); + + duty_cycle = min_t(u64, state->duty_cycle, pc->period); + val = duty_cycle * LGM_PWM_MAX_DUTY_CYCLE / pc->period; + + ret = regmap_update_bits(pc->regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_DC_MSK, + FIELD_PREP(LGM_PWM_FAN_DC_MSK, val)); + if (ret) + return ret; + + return lgm_pwm_enable(chip, 1); +} + +static void lgm_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct lgm_pwm_chip *pc = to_lgm_pwm_chip(chip); + u32 duty, val; + + state->enabled = regmap_test_bits(pc->regmap, LGM_PWM_FAN_CON0, + LGM_PWM_FAN_EN_EN); + state->polarity = PWM_POLARITY_NORMAL; + state->period = pc->period; /* fixed period */ + + regmap_read(pc->regmap, LGM_PWM_FAN_CON0, &val); + duty = FIELD_GET(LGM_PWM_FAN_DC_MSK, val); + state->duty_cycle = DIV_ROUND_UP(duty * pc->period, LGM_PWM_MAX_DUTY_CYCLE); +} + +static const struct pwm_ops lgm_pwm_ops = { + .get_state = lgm_pwm_get_state, + .apply = lgm_pwm_apply, + .owner = THIS_MODULE, +}; + +static void lgm_pwm_init(struct lgm_pwm_chip *pc) +{ + struct regmap *regmap = pc->regmap; + u32 con0_val; + + con0_val = FIELD_PREP(LGM_PWM_FAN_MODE_MSK, LGM_PWM_FAN_MODE_2WIRE); + pc->period = LGM_PWM_PERIOD_2WIRE_NS; + regmap_update_bits(regmap, LGM_PWM_FAN_CON1, LGM_PWM_FAN_MAX_RPM_MSK, + LGM_PWM_DEFAULT_RPM); + regmap_update_bits(regmap, LGM_PWM_FAN_CON0, LGM_PWM_FAN_MODE_MSK, + con0_val); +} + +static const struct regmap_config lgm_pwm_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static void lgm_clk_release(void *data) +{ + struct clk *clk = data; + + clk_disable_unprepare(clk); +} + +static int lgm_clk_enable(struct device *dev, struct clk *clk) +{ + int ret; + + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, lgm_clk_release, clk); +} + +static void lgm_reset_control_release(void *data) +{ + struct reset_control *rst = data; + + reset_control_assert(rst); +} + +static int lgm_reset_control_deassert(struct device *dev, struct reset_control *rst) +{ + int ret; + + ret = reset_control_deassert(rst); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, lgm_reset_control_release, rst); +} + +static int lgm_pwm_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct reset_control *rst; + struct lgm_pwm_chip *pc; + void __iomem *io_base; + struct clk *clk; + int ret; + + pc = devm_kzalloc(dev, sizeof(*pc), GFP_KERNEL); + if (!pc) + return -ENOMEM; + + platform_set_drvdata(pdev, pc); + + io_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + pc->regmap = devm_regmap_init_mmio(dev, io_base, &lgm_pwm_regmap_config); + if (IS_ERR(pc->regmap)) + return dev_err_probe(dev, PTR_ERR(pc->regmap), + "failed to init register map\n"); + + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n"); + + ret = lgm_clk_enable(dev, clk); + if (ret) + return dev_err_probe(dev, ret, "failed to enable clock\n"); + + rst = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(rst)) + return dev_err_probe(dev, PTR_ERR(rst), + "failed to get reset control\n"); + + ret = lgm_reset_control_deassert(dev, rst); + if (ret) + return dev_err_probe(dev, ret, "cannot deassert reset control\n"); + + pc->chip.dev = dev; + pc->chip.ops = &lgm_pwm_ops; + pc->chip.npwm = 1; + pc->chip.base = -1; + + lgm_pwm_init(pc); + + ret = pwmchip_add(&pc->chip); + if (ret < 0) + return dev_err_probe(dev, ret, "failed to add PWM chip\n"); + + return 0; +} + +static int lgm_pwm_remove(struct platform_device *pdev) +{ + struct lgm_pwm_chip *pc = platform_get_drvdata(pdev); + + return pwmchip_remove(&pc->chip); +} + +static const struct of_device_id lgm_pwm_of_match[] = { + { .compatible = "intel,lgm-pwm" }, + { } +}; +MODULE_DEVICE_TABLE(of, lgm_pwm_of_match); + +static struct platform_driver lgm_pwm_driver = { + .driver = { + .name = "intel-pwm", + .of_match_table = lgm_pwm_of_match, + }, + .probe = lgm_pwm_probe, + .remove = lgm_pwm_remove, +}; +module_platform_driver(lgm_pwm_driver); + +MODULE_LICENSE("GPL v2"); From fd3ae02bb66f091e55f363d32eca7b4039977bf5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Nov 2020 19:24:29 +0100 Subject: [PATCH 55/66] pwm: sti: Avoid conditional gotos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using gotos for conditional code complicates this code significantly. Convert the code to simple conditional blocks to increase readability. Suggested-by: Uwe Kleine-König Acked-by: Uwe Kleine-König Acked-by: Lee Jones Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sti.c | 50 ++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index eaeb38c0c0c7..3f24fb4f8596 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -590,38 +590,34 @@ static int sti_pwm_probe(struct platform_device *pdev) if (ret) return ret; - if (!cdata->pwm_num_devs) - goto skip_pwm; + if (cdata->pwm_num_devs) { + pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); + if (IS_ERR(pc->pwm_clk)) { + dev_err(dev, "failed to get PWM clock\n"); + return PTR_ERR(pc->pwm_clk); + } - pc->pwm_clk = of_clk_get_by_name(dev->of_node, "pwm"); - if (IS_ERR(pc->pwm_clk)) { - dev_err(dev, "failed to get PWM clock\n"); - return PTR_ERR(pc->pwm_clk); + ret = clk_prepare(pc->pwm_clk); + if (ret) { + dev_err(dev, "failed to prepare clock\n"); + return ret; + } } - ret = clk_prepare(pc->pwm_clk); - if (ret) { - dev_err(dev, "failed to prepare clock\n"); - return ret; + if (cdata->cpt_num_devs) { + pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); + if (IS_ERR(pc->cpt_clk)) { + dev_err(dev, "failed to get PWM capture clock\n"); + return PTR_ERR(pc->cpt_clk); + } + + ret = clk_prepare(pc->cpt_clk); + if (ret) { + dev_err(dev, "failed to prepare clock\n"); + return ret; + } } -skip_pwm: - if (!cdata->cpt_num_devs) - goto skip_cpt; - - pc->cpt_clk = of_clk_get_by_name(dev->of_node, "capture"); - if (IS_ERR(pc->cpt_clk)) { - dev_err(dev, "failed to get PWM capture clock\n"); - return PTR_ERR(pc->cpt_clk); - } - - ret = clk_prepare(pc->cpt_clk); - if (ret) { - dev_err(dev, "failed to prepare clock\n"); - return ret; - } - -skip_cpt: pc->chip.dev = dev; pc->chip.ops = &sti_pwm_ops; pc->chip.base = -1; From f14a8f0ef981387809b4d6fec857bfd8261b8f15 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Nov 2020 19:26:59 +0100 Subject: [PATCH 56/66] pwm: sti: Remove unnecessary blank line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A single blank line is enough to separate logical code blocks. Acked-by: Uwe Kleine-König Acked-by: Lee Jones Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sti.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 3f24fb4f8596..99c70e07858d 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -505,7 +505,6 @@ static int sti_pwm_probe_dt(struct sti_pwm_chip *pc) if (IS_ERR(pc->prescale_high)) return PTR_ERR(pc->prescale_high); - pc->pwm_out_en = devm_regmap_field_alloc(dev, pc->regmap, reg_fields[PWM_OUT_EN]); if (IS_ERR(pc->pwm_out_en)) From 2b1c1a5d51484f4f44d662d146e443498d0bedd2 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 11 Nov 2020 21:18:11 +0100 Subject: [PATCH 57/66] pwm: Use -EINVAL for unsupported polarity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using a mix of -EOPNOTSUPP and -ENOTSUPP, use the more standard -EINVAL to signal that the specified polarity value was invalid. Acked-by: Uwe Kleine-König Acked-by: Lee Jones Signed-off-by: Thierry Reding --- drivers/pwm/pwm-crc.c | 2 +- drivers/pwm/pwm-iqs620a.c | 2 +- drivers/pwm/pwm-rcar.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c index ecfdfac0c2d9..1e2276808b7a 100644 --- a/drivers/pwm/pwm-crc.c +++ b/drivers/pwm/pwm-crc.c @@ -64,7 +64,7 @@ static int crc_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } if (state->polarity != PWM_POLARITY_NORMAL) - return -EOPNOTSUPP; + return -EINVAL; if (pwm_is_enabled(pwm) && !state->enabled) { err = regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0); diff --git a/drivers/pwm/pwm-iqs620a.c b/drivers/pwm/pwm-iqs620a.c index 7d33e3646436..5ede8255926e 100644 --- a/drivers/pwm/pwm-iqs620a.c +++ b/drivers/pwm/pwm-iqs620a.c @@ -50,7 +50,7 @@ static int iqs620_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, int ret; if (state->polarity != PWM_POLARITY_NORMAL) - return -ENOTSUPP; + return -EINVAL; if (state->period < IQS620_PWM_PERIOD_NS) return -EINVAL; diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 3e23f1e4e1f6..002ab79a7ec2 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -168,7 +168,7 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* This HW/driver only supports normal polarity */ if (state->polarity != PWM_POLARITY_NORMAL) - return -ENOTSUPP; + return -EINVAL; if (!state->enabled) { rcar_pwm_disable(rp); From 71d4b833da7fb0f80f78a045e5796c9e3a880f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 18 Nov 2020 10:45:08 +0100 Subject: [PATCH 58/66] pwm: Fix dependencies on HAS_IOMEM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drivers making use of IO remapping must depend on HAS_IOMEM. Reported-by: kernel test robot Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b2a87fd7e8fb..ab0606bbe234 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -53,8 +53,8 @@ config PWM_AB8500 config PWM_ATMEL tristate "Atmel PWM support" - depends on OF depends on ARCH_AT91 || COMPILE_TEST + depends on HAS_IOMEM && OF help Generic PWM framework driver for Atmel SoC. @@ -89,7 +89,7 @@ config PWM_ATMEL_TCB config PWM_BCM_IPROC tristate "iProc PWM support" depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on COMMON_CLK + depends on COMMON_CLK && HAS_IOMEM default ARCH_BCM_IPROC help Generic PWM framework driver for Broadcom iProc PWM block. This @@ -112,6 +112,7 @@ config PWM_BCM_KONA config PWM_BCM2835 tristate "BCM2835 PWM support" depends on ARCH_BCM2835 || ARCH_BRCMSTB || COMPILE_TEST + depends on HAS_IOMEM help PWM framework driver for BCM2835 controller (Raspberry Pi) @@ -121,6 +122,7 @@ config PWM_BCM2835 config PWM_BERLIN tristate "Marvell Berlin PWM support" depends on ARCH_BERLIN || COMPILE_TEST + depends on HAS_IOMEM help PWM framework driver for Marvell Berlin SoCs. @@ -130,6 +132,7 @@ config PWM_BERLIN config PWM_BRCMSTB tristate "Broadcom STB PWM support" depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for the Broadcom Set-top-Box SoCs (BCM7xxx). @@ -173,6 +176,7 @@ config PWM_DWC config PWM_EP93XX tristate "Cirrus Logic EP93xx PWM support" depends on ARCH_EP93XX || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for Cirrus Logic EP93xx. @@ -194,6 +198,7 @@ config PWM_FSL_FTM config PWM_HIBVT tristate "HiSilicon BVT PWM support" depends on ARCH_HISI || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for HiSilicon BVT SoCs. @@ -216,6 +221,7 @@ config PWM_IMG config PWM_IMX1 tristate "i.MX1 PWM support" depends on ARCH_MXC || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for i.MX1 and i.MX21 @@ -225,6 +231,7 @@ config PWM_IMX1 config PWM_IMX27 tristate "i.MX27 PWM support" depends on ARCH_MXC || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for i.MX27 and later i.MX SoCs. @@ -297,6 +304,7 @@ config PWM_LP3943 config PWM_LPC18XX_SCT tristate "LPC18xx/43xx PWM/SCT support" depends on ARCH_LPC18XX || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for NXP LPC18xx PWM/SCT which supports 16 channels. @@ -309,6 +317,7 @@ config PWM_LPC18XX_SCT config PWM_LPC32XX tristate "LPC32XX PWM support" depends on ARCH_LPC32XX || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two PWM controllers. @@ -317,11 +326,13 @@ config PWM_LPC32XX will be called pwm-lpc32xx. config PWM_LPSS + depends on HAS_IOMEM tristate config PWM_LPSS_PCI tristate "Intel LPSS PWM PCI driver" depends on X86 && PCI + depends on HAS_IOMEM select PWM_LPSS help The PCI driver for Intel Low Power Subsystem PWM controller. @@ -332,6 +343,7 @@ config PWM_LPSS_PCI config PWM_LPSS_PLATFORM tristate "Intel LPSS PWM platform driver" depends on X86 && ACPI + depends on HAS_IOMEM select PWM_LPSS help The platform driver for Intel Low Power Subsystem PWM controller. @@ -342,7 +354,7 @@ config PWM_LPSS_PLATFORM config PWM_MESON tristate "Amlogic Meson PWM driver" depends on ARCH_MESON || COMPILE_TEST - depends on COMMON_CLK + depends on COMMON_CLK && HAS_IOMEM help The platform driver for Amlogic Meson PWM controller. @@ -363,6 +375,7 @@ config PWM_MTK_DISP config PWM_MEDIATEK tristate "MediaTek PWM support" depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for Mediatek ARM SoC. @@ -371,8 +384,8 @@ config PWM_MEDIATEK config PWM_MXS tristate "Freescale MXS PWM support" - depends on OF depends on ARCH_MXS || COMPILE_TEST + depends on HAS_IOMEM && OF select STMP_DEVICE help Generic PWM framework driver for Freescale MXS. @@ -403,6 +416,7 @@ config PWM_PCA9685 config PWM_PXA tristate "PXA PWM support" depends on ARCH_PXA || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for PXA. @@ -434,6 +448,7 @@ config PWM_RENESAS_TPU config PWM_ROCKCHIP tristate "Rockchip PWM support" depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for the PWM controller found on Rockchip SoCs. @@ -441,6 +456,7 @@ config PWM_ROCKCHIP config PWM_SAMSUNG tristate "Samsung PWM support" depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for Samsung. @@ -450,7 +466,7 @@ config PWM_SAMSUNG config PWM_SIFIVE tristate "SiFive PWM support" depends on OF - depends on COMMON_CLK + depends on COMMON_CLK && HAS_IOMEM depends on RISCV || COMPILE_TEST help Generic PWM framework driver for SiFive SoCs. @@ -471,7 +487,7 @@ config PWM_SL28CPLD config PWM_SPEAR tristate "STMicroelectronics SPEAr PWM support" depends on PLAT_SPEAR || COMPILE_TEST - depends on OF + depends on HAS_IOMEM && OF help Generic PWM framework driver for the PWM controller on ST SPEAr SoCs. @@ -493,7 +509,7 @@ config PWM_SPRD config PWM_STI tristate "STiH4xx PWM support" depends on ARCH_STI || COMPILE_TEST - depends on OF + depends on HAS_IOMEM && OF help Generic PWM framework driver for STiH4xx SoCs. @@ -539,6 +555,7 @@ config PWM_SUN4I config PWM_TEGRA tristate "NVIDIA Tegra PWM support" depends on ARCH_TEGRA || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for the PWFM controller found on NVIDIA Tegra SoCs. @@ -549,6 +566,7 @@ config PWM_TEGRA config PWM_TIECAP tristate "ECAP PWM support" depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST + depends on HAS_IOMEM help PWM driver support for the ECAP APWM controller found on TI SOCs @@ -558,6 +576,7 @@ config PWM_TIECAP config PWM_TIEHRPWM tristate "EHRPWM PWM support" depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_K3 || COMPILE_TEST + depends on HAS_IOMEM help PWM driver support for the EHRPWM controller found on TI SOCs @@ -585,6 +604,7 @@ config PWM_TWL_LED config PWM_VT8500 tristate "vt8500 PWM support" depends on ARCH_VT8500 || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for vt8500. @@ -594,6 +614,7 @@ config PWM_VT8500 config PWM_ZX tristate "ZTE ZX PWM support" depends on ARCH_ZX || COMPILE_TEST + depends on HAS_IOMEM help Generic PWM framework driver for ZTE ZX family SoCs. From aa43edcbc898afffb061f560d928d43bd55f4dc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 18 Nov 2020 10:45:09 +0100 Subject: [PATCH 59/66] pwm: lpss: Make compilable with COMPILE_TEST MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All used ACPI functions have dummy implementations, and there is no hard dependency on x86. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index ab0606bbe234..0937e1c047ac 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -331,8 +331,8 @@ config PWM_LPSS config PWM_LPSS_PCI tristate "Intel LPSS PWM PCI driver" - depends on X86 && PCI - depends on HAS_IOMEM + depends on X86 || COMPILE_TEST + depends on HAS_IOMEM && PCI select PWM_LPSS help The PCI driver for Intel Low Power Subsystem PWM controller. @@ -342,7 +342,7 @@ config PWM_LPSS_PCI config PWM_LPSS_PLATFORM tristate "Intel LPSS PWM platform driver" - depends on X86 && ACPI + depends on (X86 && ACPI) || COMPILE_TEST depends on HAS_IOMEM select PWM_LPSS help From 765edf0bf019ff8a7ae2dedbccd8af370b0856b5 Mon Sep 17 00:00:00 2001 From: Soham Biswas Date: Wed, 18 Nov 2020 20:21:12 +0530 Subject: [PATCH 60/66] pwm: core: Use octal permission MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Permission bits are easier readable in octal than with using the symbolic names. Fixes the following warning generated by checkpatch: WARNING: Symbolic permissions 'S_IRUGO' are not preferred. Consider using octal permissions '0444'. #1341: FILE: drivers/pwm/core.c:1341: + debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, Signed-off-by: Soham Biswas Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 1f16f5365d3c..a8eff4b3ee36 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -1338,7 +1338,7 @@ DEFINE_SEQ_ATTRIBUTE(pwm_debugfs); static int __init pwm_debugfs_init(void) { - debugfs_create_file("pwm", S_IFREG | S_IRUGO, NULL, NULL, + debugfs_create_file("pwm", S_IFREG | 0444, NULL, NULL, &pwm_debugfs_fops); return 0; From bb72e1dbae0e759252fcdb4a97917200e165bf91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 16 Nov 2020 10:08:04 +0100 Subject: [PATCH 61/66] pwm: keembay: Fix build failure with -Os MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver used this construct: #define KMB_PWM_LEADIN_MASK GENMASK(30, 0) static inline void keembay_pwm_update_bits(struct keembay_pwm *priv, u32 mask, u32 val, u32 offset) { u32 buff = readl(priv->base + offset); buff = u32_replace_bits(buff, val, mask); writel(buff, priv->base + offset); } ... keembay_pwm_update_bits(priv, KMB_PWM_LEADIN_MASK, 0, KMB_PWM_LEADIN_OFFSET(pwm->hwpwm)); With CONFIG_CC_OPTIMIZE_FOR_SIZE the compiler (here: gcc 10.2.0) this triggers: In file included from /home/uwe/gsrc/linux/drivers/pwm/pwm-keembay.c:16: In function ‘field_multiplier’, inlined from ‘keembay_pwm_update_bits’ at /home/uwe/gsrc/linux/include/linux/bitfield.h:124:17: /home/uwe/gsrc/linux/include/linux/bitfield.h:119:3: error: call to ‘__bad_mask’ declared with attribute error: bad bitfield mask 119 | __bad_mask(); | ^~~~~~~~~~~~ In function ‘field_multiplier’, inlined from ‘keembay_pwm_update_bits’ at /home/uwe/gsrc/linux/include/linux/bitfield.h:154:1: /home/uwe/gsrc/linux/include/linux/bitfield.h:119:3: error: call to ‘__bad_mask’ declared with attribute error: bad bitfield mask 119 | __bad_mask(); | ^~~~~~~~~~~~ The compiler doesn't seem to be able to notice that with field being 0x3ffffff the expression if ((field | (field - 1)) & ((field | (field - 1)) + 1)) __bad_mask(); can be optimized away. So use __always_inline and document the problem in a comment to fix this. Reported-by: kernel test robot Signed-off-by: Uwe Kleine-König Tested-by: Vijayakannan Ayyathurai Signed-off-by: Thierry Reding --- drivers/pwm/pwm-keembay.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-keembay.c b/drivers/pwm/pwm-keembay.c index 2b6dd070daa4..cdfdef66ff8e 100644 --- a/drivers/pwm/pwm-keembay.c +++ b/drivers/pwm/pwm-keembay.c @@ -63,7 +63,12 @@ static int keembay_clk_enable(struct device *dev, struct clk *clk) return devm_add_action_or_reset(dev, keembay_clk_unprepare, clk); } -static inline void keembay_pwm_update_bits(struct keembay_pwm *priv, u32 mask, +/* + * With gcc 10, CONFIG_CC_OPTIMIZE_FOR_SIZE and only "inline" instead of + * "__always_inline" this fails to compile because the compiler doesn't notice + * for all valid masks (e.g. KMB_PWM_LEADIN_MASK) that they are ok. + */ +static __always_inline void keembay_pwm_update_bits(struct keembay_pwm *priv, u32 mask, u32 val, u32 offset) { u32 buff = readl(priv->base + offset); From 2f81b51d0d02074502ad27424c228ca760823668 Mon Sep 17 00:00:00 2001 From: Lino Sanfilippo Date: Wed, 9 Dec 2020 21:48:25 +0100 Subject: [PATCH 62/66] pwm: bcm2835: Support apply function for atomic configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the newer .apply function of pwm_ops instead of .config, .enable, .disable and .set_polarity. This guarantees atomic changes of the pwm controller configuration. It also reduces the size of the driver. Since now period is a 64 bit value, add an extra check to reject periods that exceed the possible max value for the 32 bit register. This has been tested on a Raspberry PI 4. Signed-off-by: Lino Sanfilippo Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 71 ++++++++++++++------------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index bc018daf1488..6ff5f04b3e07 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -58,13 +58,15 @@ static void bcm2835_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) writel(value, pc->base + PWM_CONTROL); } -static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int bcm2835_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) { + struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); unsigned long rate = clk_get_rate(pc->clk); + unsigned long long period; unsigned long scaler; - u32 period; + u32 val; if (!rate) { dev_err(pc->dev, "failed to get clock rate\n"); @@ -72,54 +74,34 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, } scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate); - period = DIV_ROUND_CLOSEST(period_ns, scaler); + /* set period */ + period = DIV_ROUND_CLOSEST_ULL(state->period, scaler); - if (period < PERIOD_MIN) + /* dont accept a period that is too small or has been truncated */ + if ((period < PERIOD_MIN) || (period > U32_MAX)) return -EINVAL; - writel(DIV_ROUND_CLOSEST(duty_ns, scaler), - pc->base + DUTY(pwm->hwpwm)); writel(period, pc->base + PERIOD(pwm->hwpwm)); - return 0; -} + /* set duty cycle */ + val = DIV_ROUND_CLOSEST_ULL(state->duty_cycle, scaler); + writel(val, pc->base + DUTY(pwm->hwpwm)); -static int bcm2835_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); - u32 value; + /* set polarity */ + val = readl(pc->base + PWM_CONTROL); - value = readl(pc->base + PWM_CONTROL); - value |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm); - writel(value, pc->base + PWM_CONTROL); - - return 0; -} - -static void bcm2835_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) -{ - struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); - u32 value; - - value = readl(pc->base + PWM_CONTROL); - value &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm)); - writel(value, pc->base + PWM_CONTROL); -} - -static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, - enum pwm_polarity polarity) -{ - struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); - u32 value; - - value = readl(pc->base + PWM_CONTROL); - - if (polarity == PWM_POLARITY_NORMAL) - value &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); + if (state->polarity == PWM_POLARITY_NORMAL) + val &= ~(PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm)); else - value |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm); + val |= PWM_POLARITY << PWM_CONTROL_SHIFT(pwm->hwpwm); - writel(value, pc->base + PWM_CONTROL); + /* enable/disable */ + if (state->enabled) + val |= PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm); + else + val &= ~(PWM_ENABLE << PWM_CONTROL_SHIFT(pwm->hwpwm)); + + writel(val, pc->base + PWM_CONTROL); return 0; } @@ -127,10 +109,7 @@ static int bcm2835_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, static const struct pwm_ops bcm2835_pwm_ops = { .request = bcm2835_pwm_request, .free = bcm2835_pwm_free, - .config = bcm2835_pwm_config, - .enable = bcm2835_pwm_enable, - .disable = bcm2835_pwm_disable, - .set_polarity = bcm2835_set_polarity, + .apply = bcm2835_pwm_apply, .owner = THIS_MODULE, }; From 1ce65396e6b2386b4fd54f87beff0647a772e1cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 7 Dec 2020 15:13:24 +0100 Subject: [PATCH 63/66] pwm: imx27: Fix overflow for bigger periods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The second parameter of do_div is an u32 and NSEC_PER_SEC * prescale overflows this for bigger periods. Assuming the usual pwm input clk rate of 66 MHz this happens starting at requested period > 606060 ns. Splitting the division into two operations doesn't loose any precision. It doesn't need to be feared that c / NSEC_PER_SEC doesn't fit into the unsigned long variable "duty_cycles" because in this case the assignment above to period_cycles would already have been overflowing as period >= duty_cycle and then the calculation is moot anyhow. Fixes: aef1a3799b5c ("pwm: imx27: Fix rounding behavior") Signed-off-by: Uwe Kleine-König Tested-by: Johannes Pointner Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx27.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index ceaed0378de7..18055326a2f3 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -235,8 +235,9 @@ static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, period_cycles /= prescale; c = clkrate * state->duty_cycle; - do_div(c, NSEC_PER_SEC * prescale); + do_div(c, NSEC_PER_SEC); duty_cycles = c; + duty_cycles /= prescale; /* * according to imx pwm RM, the real period value should be PERIOD From 3df23a316c4a5d1764b034c71c29d67a17d5299f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 5 Dec 2020 17:19:24 +0100 Subject: [PATCH 64/66] pwm: Remove unused function pwmchip_add_inversed() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is only defined with CONFIG_PWM unset and was introduced together with pwmchip_add_with_polarity() (which is only defined with CONFIG_PWM enabled). I guess the series that introduced pwmchip_add_with_polarity() had a different concept in earlier revisions and the !CONFIG_PWM part was just not updated accordingly. Given that there is no implementation for pwmchip_add_with_polarity() without CONFIG_PWM, just drop pwmchip_add_inversed() instead of renaming it to pwmchip_add_with_polarity(). Signed-off-by: Uwe Kleine-König Acked-by: Lee Jones Signed-off-by: Thierry Reding --- include/linux/pwm.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index a13ff383fa1d..e4d84d4db293 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -473,11 +473,6 @@ static inline int pwmchip_add(struct pwm_chip *chip) return -EINVAL; } -static inline int pwmchip_add_inversed(struct pwm_chip *chip) -{ - return -EINVAL; -} - static inline int pwmchip_remove(struct pwm_chip *chip) { return -EINVAL; From edf7f80e780e50bb5711d4c112b721517d0ff73e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 4 Dec 2020 13:44:35 +0100 Subject: [PATCH 65/66] pwm: sl28cpld: Set driver data before registering the PWM chip It is good practice to set the driver data before registering a device with a subsystem because the subsystem or the driver core may call back into the driver implementation. This is not currently an issue, but to prevent future changes from causing this to break unexpectedly, make sure that the driver data is set before the PWM chip registration. Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sl28cpld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-sl28cpld.c b/drivers/pwm/pwm-sl28cpld.c index 5046b6b7fd35..c5866a2b47b5 100644 --- a/drivers/pwm/pwm-sl28cpld.c +++ b/drivers/pwm/pwm-sl28cpld.c @@ -230,6 +230,8 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev) chip->base = -1; chip->npwm = 1; + platform_set_drvdata(pdev, priv); + ret = pwmchip_add(&priv->pwm_chip); if (ret) { dev_err(&pdev->dev, "failed to add PWM chip (%pe)", @@ -237,8 +239,6 @@ static int sl28cpld_pwm_probe(struct platform_device *pdev) return ret; } - platform_set_drvdata(pdev, priv); - return 0; } From 6eefb79d6f5bc4086bd02c76f1072dd4a8d9d9f6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 16 Dec 2020 18:33:55 +0100 Subject: [PATCH 66/66] pwm: sun4i: Remove erroneous else branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit d3817a647059 ("pwm: sun4i: Remove redundant needs_delay") changed the logic of an else branch so that the PWM_EN and PWM_CLK_GATING bits are now cleared if the PWM is to be disabled, whereas previously the condition was always false, and hence the branch never got executed. This code is reported causing backlight issues on boards based on the Allwinner A20 SoC. Fix this by removing the else branch, which restores the behaviour prior to the offending commit. Note that the PWM_EN and PWM_CLK_GATING bits still get cleared later in sun4i_pwm_apply() if the PWM is to be disabled. Fixes: d3817a647059 ("pwm: sun4i: Remove redundant needs_delay") Reported-by: Taras Galchenko Suggested-by: Taras Galchenko Tested-by: Taras Galchenko Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sun4i.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index cc1eb0818648..ce5c4fc8da6f 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -294,12 +294,8 @@ static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, ctrl |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - if (state->enabled) { + if (state->enabled) ctrl |= BIT_CH(PWM_EN, pwm->hwpwm); - } else { - ctrl &= ~BIT_CH(PWM_EN, pwm->hwpwm); - ctrl &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm); - } sun4i_pwm_writel(sun4i_pwm, ctrl, PWM_CTRL_REG);