From a315614b68993318f6913cc28b9b4e472ebbdf26 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 18 Jul 2019 09:32:05 +0800 Subject: pwm: mxs: Use devm_platform_ioremap_resource() to simplify code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together, to simplify the code. Signed-off-by: Anson Huang Reviewed-by: Dong Aisheng Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mxs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index 04c0f6b95c1a..b14376b47ac8 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -126,15 +126,13 @@ static int mxs_pwm_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mxs_pwm_chip *mxs; - struct resource *res; int ret; mxs = devm_kzalloc(&pdev->dev, sizeof(*mxs), GFP_KERNEL); if (!mxs) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mxs->base = devm_ioremap_resource(&pdev->dev, res); + mxs->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mxs->base)) return PTR_ERR(mxs->base); -- cgit v1.2.3 From f6abac0379b8368519f28016c8c8821b8bd17f5e Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Thu, 18 Jul 2019 15:51:11 +0800 Subject: pwm: sifive: Remove redundant error message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit devm_ioremap_resource() already outputs an error message, so remove the extra error message on failure. Signed-off-by: Ding Xiang Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sifive.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index a7c107f19e66..bb4f02ce4f94 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -250,10 +250,8 @@ static int pwm_sifive_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ddata->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(ddata->regs)) { - dev_err(dev, "Unable to map IO resources\n"); + if (IS_ERR(ddata->regs)) return PTR_ERR(ddata->regs); - } ddata->clk = devm_clk_get(dev, NULL); if (IS_ERR(ddata->clk)) { -- cgit v1.2.3 From 3b442c60cf9766c76bc3c1e44e3e387853074a08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 30 Jul 2019 14:32:29 +0200 Subject: pwm: jz4740: Document known limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The JZ4740 PWM implementation doesn't fulfill the (up to now insufficiently documented) requirements of the PWM API. At least document them in the driver. Signed-off-by: Uwe Kleine-König Reviewed-by: Paul Cercueil Signed-off-by: Thierry Reding --- drivers/pwm/pwm-jz4740.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index f901e8a0d33d..9d444d012f92 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -2,6 +2,11 @@ /* * Copyright (C) 2010, Lars-Peter Clausen * JZ4740 platform PWM support + * + * Limitations: + * - The .apply callback doesn't complete the currently running period before + * reconfiguring the hardware. + * - Each period starts with the inactive part. */ #include -- cgit v1.2.3 From f6960976c465179cd1b64dfae2edfb647820af1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 30 Jul 2019 14:45:27 +0200 Subject: pwm: imx: Document known limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-imx27.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 434a351fb626..91c23cbbc167 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -3,6 +3,10 @@ * simple driver for PWM (Pulse Width Modulator) controller * * Derived from pxa PWM driver by eric miao + * + * Limitations: + * - When disabled the output is driven to 0 independent of the configured + * polarity. */ #include -- cgit v1.2.3 From fb5a35dbee8d6bd2ff638b7ebaf540b86860ee0a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 30 Jul 2019 11:15:36 -0700 Subject: pwm: Remove dev_err() usage after platform_get_irq() We don't need dev_err() messages when platform_get_irq() fails now that platform_get_irq() prints an error message itself when something goes wrong. Let's remove these prints with a simple semantic patch. // @@ expression ret; struct platform_device *E; @@ ret = ( platform_get_irq(E, ...) | platform_get_irq_byname(E, ...) ); if ( \( ret < 0 \| ret <= 0 \) ) { ( -if (ret != -EPROBE_DEFER) -{ ... -dev_err(...); -... } | ... -dev_err(...); ) ... } // While we're here, remove braces on if statements that only have one statement (manually). Cc: Thierry Reding Cc: linux-pwm@vger.kernel.org Cc: Greg Kroah-Hartman Signed-off-by: Stephen Boyd Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sti.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c index 20450e34ad57..1508616d794c 100644 --- a/drivers/pwm/pwm-sti.c +++ b/drivers/pwm/pwm-sti.c @@ -564,10 +564,8 @@ static int sti_pwm_probe(struct platform_device *pdev) return PTR_ERR(pc->regmap); irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to obtain IRQ\n"); + if (irq < 0) return irq; - } ret = devm_request_irq(&pdev->dev, irq, sti_pwm_interrupt, 0, pdev->name, pc); -- cgit v1.2.3 From 8d190728fd8e272b733e1575e000fc1982b5d9b2 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Mon, 5 Aug 2019 14:58:48 +0200 Subject: pwm: mediatek: Add MT8516 SoC support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the compatible and the platform data to support PWM on the MT8516 SoC. Signed-off-by: Fabien Parent Reviewed-by: Matthias Brugger Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index eb6674ce995f..6697e30811e7 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -302,11 +302,18 @@ static const struct mtk_pwm_platform_data mt7628_pwm_data = { .has_clks = false, }; +static const struct mtk_pwm_platform_data mt8516_pwm_data = { + .num_pwms = 5, + .pwm45_fixup = false, + .has_clks = true, +}; + static const struct of_device_id mtk_pwm_of_match[] = { { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, + { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, { }, }; MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); -- cgit v1.2.3 From 8aae4b02e8a6dd138afd2b54d9984d17685b0364 Mon Sep 17 00:00:00 2001 From: Baolin Wang Date: Wed, 14 Aug 2019 20:46:11 +0800 Subject: pwm: sprd: Add Spreadtrum PWM support This patch adds the Spreadtrum PWM support, which provides maximum 4 channels. Signed-off-by: Neo Hou Signed-off-by: Baolin Wang Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 11 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-sprd.c | 309 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+) create mode 100644 drivers/pwm/pwm-sprd.c (limited to 'drivers') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index a7e57516959e..31dfc88ef362 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -423,6 +423,17 @@ config PWM_SPEAR To compile this driver as a module, choose M here: the module will be called pwm-spear. +config PWM_SPRD + tristate "Spreadtrum PWM support" + depends on ARCH_SPRD || COMPILE_TEST + depends on HAS_IOMEM + help + Generic PWM framework driver for the PWM controller on + Spreadtrum SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-sprd. + config PWM_STI tristate "STiH4xx PWM support" depends on ARCH_STI diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 76b555b51887..26326adf71d7 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o +obj-$(CONFIG_PWM_SPRD) += pwm-sprd.o obj-$(CONFIG_PWM_STI) += pwm-sti.o obj-$(CONFIG_PWM_STM32) += pwm-stm32.o obj-$(CONFIG_PWM_STM32_LP) += pwm-stm32-lp.o diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c new file mode 100644 index 000000000000..68c2d9f0411b --- /dev/null +++ b/drivers/pwm/pwm-sprd.c @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Spreadtrum Communications Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SPRD_PWM_PRESCALE 0x0 +#define SPRD_PWM_MOD 0x4 +#define SPRD_PWM_DUTY 0x8 +#define SPRD_PWM_ENABLE 0x18 + +#define SPRD_PWM_MOD_MAX GENMASK(7, 0) +#define SPRD_PWM_DUTY_MSK GENMASK(15, 0) +#define SPRD_PWM_PRESCALE_MSK GENMASK(7, 0) +#define SPRD_PWM_ENABLE_BIT BIT(0) + +#define SPRD_PWM_CHN_NUM 4 +#define SPRD_PWM_REGS_SHIFT 5 +#define SPRD_PWM_CHN_CLKS_NUM 2 +#define SPRD_PWM_CHN_OUTPUT_CLK 1 + +struct sprd_pwm_chn { + struct clk_bulk_data clks[SPRD_PWM_CHN_CLKS_NUM]; + u32 clk_rate; +}; + +struct sprd_pwm_chip { + void __iomem *base; + struct device *dev; + struct pwm_chip chip; + int num_pwms; + struct sprd_pwm_chn chn[SPRD_PWM_CHN_NUM]; +}; + +/* + * The list of clocks required by PWM channels, and each channel has 2 clocks: + * enable clock and pwm clock. + */ +static const char * const sprd_pwm_clks[] = { + "enable0", "pwm0", + "enable1", "pwm1", + "enable2", "pwm2", + "enable3", "pwm3", +}; + +static u32 sprd_pwm_read(struct sprd_pwm_chip *spc, u32 hwid, u32 reg) +{ + u32 offset = reg + (hwid << SPRD_PWM_REGS_SHIFT); + + return readl_relaxed(spc->base + offset); +} + +static void sprd_pwm_write(struct sprd_pwm_chip *spc, u32 hwid, + u32 reg, u32 val) +{ + u32 offset = reg + (hwid << SPRD_PWM_REGS_SHIFT); + + writel_relaxed(val, spc->base + offset); +} + +static void sprd_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct sprd_pwm_chip *spc = + container_of(chip, struct sprd_pwm_chip, chip); + struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm]; + u32 val, duty, prescale; + u64 tmp; + int ret; + + /* + * The clocks to PWM channel has to be enabled first before + * reading to the registers. + */ + ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM, chn->clks); + if (ret) { + dev_err(spc->dev, "failed to enable pwm%u clocks\n", + pwm->hwpwm); + return; + } + + val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_ENABLE); + if (val & SPRD_PWM_ENABLE_BIT) + state->enabled = true; + else + state->enabled = false; + + /* + * The hardware provides a counter that is feed by the source clock. + * The period length is (PRESCALE + 1) * MOD counter steps. + * The duty cycle length is (PRESCALE + 1) * DUTY counter steps. + * Thus the period_ns and duty_ns calculation formula should be: + * period_ns = NSEC_PER_SEC * (prescale + 1) * mod / clk_rate + * duty_ns = NSEC_PER_SEC * (prescale + 1) * duty / clk_rate + */ + val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_PRESCALE); + prescale = val & SPRD_PWM_PRESCALE_MSK; + tmp = (prescale + 1) * NSEC_PER_SEC * SPRD_PWM_MOD_MAX; + state->period = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate); + + val = sprd_pwm_read(spc, pwm->hwpwm, SPRD_PWM_DUTY); + duty = val & SPRD_PWM_DUTY_MSK; + tmp = (prescale + 1) * NSEC_PER_SEC * duty; + state->duty_cycle = DIV_ROUND_CLOSEST_ULL(tmp, chn->clk_rate); + + /* Disable PWM clocks if the PWM channel is not in enable state. */ + if (!state->enabled) + clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks); +} + +static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm]; + u32 prescale, duty; + u64 tmp; + + /* + * The hardware provides a counter that is feed by the source clock. + * The period length is (PRESCALE + 1) * MOD counter steps. + * The duty cycle length is (PRESCALE + 1) * DUTY counter steps. + * + * To keep the maths simple we're always using MOD = SPRD_PWM_MOD_MAX. + * The value for PRESCALE is selected such that the resulting period + * gets the maximal length not bigger than the requested one with the + * given settings (MOD = SPRD_PWM_MOD_MAX and input clock). + */ + duty = duty_ns * SPRD_PWM_MOD_MAX / period_ns; + + tmp = (u64)chn->clk_rate * period_ns; + do_div(tmp, NSEC_PER_SEC); + prescale = DIV_ROUND_CLOSEST_ULL(tmp, SPRD_PWM_MOD_MAX) - 1; + if (prescale > SPRD_PWM_PRESCALE_MSK) + prescale = SPRD_PWM_PRESCALE_MSK; + + /* + * Note: Writing DUTY triggers the hardware to actually apply the + * values written to MOD and DUTY to the output, so must keep writing + * DUTY last. + * + * The hardware can ensures that current running period is completed + * before changing a new configuration to avoid mixed settings. + */ + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_PRESCALE, prescale); + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_MOD, SPRD_PWM_MOD_MAX); + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_DUTY, duty); + + return 0; +} + +static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct sprd_pwm_chip *spc = + container_of(chip, struct sprd_pwm_chip, chip); + struct sprd_pwm_chn *chn = &spc->chn[pwm->hwpwm]; + struct pwm_state *cstate = &pwm->state; + int ret; + + if (state->enabled) { + if (!cstate->enabled) { + /* + * The clocks to PWM channel has to be enabled first + * before writing to the registers. + */ + ret = clk_bulk_prepare_enable(SPRD_PWM_CHN_CLKS_NUM, + chn->clks); + if (ret) { + dev_err(spc->dev, + "failed to enable pwm%u clocks\n", + pwm->hwpwm); + return ret; + } + } + + if (state->period != cstate->period || + state->duty_cycle != cstate->duty_cycle) { + ret = sprd_pwm_config(spc, pwm, state->duty_cycle, + state->period); + if (ret) + return ret; + } + + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_ENABLE, 1); + } else if (cstate->enabled) { + /* + * Note: After setting SPRD_PWM_ENABLE to zero, the controller + * will not wait for current period to be completed, instead it + * will stop the PWM channel immediately. + */ + sprd_pwm_write(spc, pwm->hwpwm, SPRD_PWM_ENABLE, 0); + + clk_bulk_disable_unprepare(SPRD_PWM_CHN_CLKS_NUM, chn->clks); + } + + return 0; +} + +static const struct pwm_ops sprd_pwm_ops = { + .apply = sprd_pwm_apply, + .get_state = sprd_pwm_get_state, + .owner = THIS_MODULE, +}; + +static int sprd_pwm_clk_init(struct sprd_pwm_chip *spc) +{ + struct clk *clk_pwm; + int ret, i; + + for (i = 0; i < SPRD_PWM_CHN_NUM; i++) { + struct sprd_pwm_chn *chn = &spc->chn[i]; + int j; + + for (j = 0; j < SPRD_PWM_CHN_CLKS_NUM; ++j) + chn->clks[j].id = + sprd_pwm_clks[i * SPRD_PWM_CHN_CLKS_NUM + j]; + + ret = devm_clk_bulk_get(spc->dev, SPRD_PWM_CHN_CLKS_NUM, + chn->clks); + if (ret) { + if (ret == -ENOENT) + break; + + if (ret != -EPROBE_DEFER) + dev_err(spc->dev, + "failed to get channel clocks\n"); + + return ret; + } + + clk_pwm = chn->clks[SPRD_PWM_CHN_OUTPUT_CLK].clk; + chn->clk_rate = clk_get_rate(clk_pwm); + } + + if (!i) { + dev_err(spc->dev, "no available PWM channels\n"); + return -ENODEV; + } + + spc->num_pwms = i; + + return 0; +} + +static int sprd_pwm_probe(struct platform_device *pdev) +{ + struct sprd_pwm_chip *spc; + int ret; + + spc = devm_kzalloc(&pdev->dev, sizeof(*spc), GFP_KERNEL); + if (!spc) + return -ENOMEM; + + spc->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(spc->base)) + return PTR_ERR(spc->base); + + spc->dev = &pdev->dev; + platform_set_drvdata(pdev, spc); + + ret = sprd_pwm_clk_init(spc); + if (ret) + return ret; + + spc->chip.dev = &pdev->dev; + spc->chip.ops = &sprd_pwm_ops; + spc->chip.base = -1; + spc->chip.npwm = spc->num_pwms; + + ret = pwmchip_add(&spc->chip); + if (ret) + dev_err(&pdev->dev, "failed to add PWM chip\n"); + + return ret; +} + +static int sprd_pwm_remove(struct platform_device *pdev) +{ + struct sprd_pwm_chip *spc = platform_get_drvdata(pdev); + + return pwmchip_remove(&spc->chip); +} + +static const struct of_device_id sprd_pwm_of_match[] = { + { .compatible = "sprd,ums512-pwm", }, + { }, +}; +MODULE_DEVICE_TABLE(of, sprd_pwm_of_match); + +static struct platform_driver sprd_pwm_driver = { + .driver = { + .name = "sprd-pwm", + .of_match_table = sprd_pwm_of_match, + }, + .probe = sprd_pwm_probe, + .remove = sprd_pwm_remove, +}; + +module_platform_driver(sprd_pwm_driver); + +MODULE_DESCRIPTION("Spreadtrum PWM Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From c79468b8955b4924b5aca858247395265201ac42 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 19 Aug 2019 15:20:12 +0900 Subject: pwm: rcar: Remove a redundant condition in rcar_pwm_apply() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the rcar_pwm_apply() has already checked whether state->enabled is set or not, this patch removes a redundant condition. Signed-off-by: Yoshihiro Shimoda Reviewed-by: Geert Uytterhoeven Reviewed-by: Uwe Kleine-König Reviewed-by: Simon Horman Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rcar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 5b2b8ecc354c..c8cd43f91efc 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -187,7 +187,7 @@ static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */ rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR); - if (!ret && state->enabled) + if (!ret) ret = rcar_pwm_enable(rp); return ret; -- cgit v1.2.3 From 4537e52a526698f503dcb151234414cfa46d534b Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 24 Aug 2019 16:09:46 +0200 Subject: pwm: bcm2835: Suppress error message for invalid period_ns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PWM config can be triggered via sysfs, so we better suppress the error message in case of an invalid period to avoid kernel log spamming. Signed-off-by: Stefan Wahren Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index f6fe0b922e1e..52763063c100 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -72,11 +72,8 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, scaler = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate); - if (period_ns <= MIN_PERIOD) { - dev_err(pc->dev, "period %d not supported, minimum %d\n", - period_ns, MIN_PERIOD); + if (period_ns <= MIN_PERIOD) return -EINVAL; - } writel(DIV_ROUND_CLOSEST(duty_ns, scaler), pc->base + DUTY(pwm->hwpwm)); -- cgit v1.2.3 From 7e9713af316187f323b25ebf7eb1a8f03425e7e9 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 24 Aug 2019 16:09:47 +0200 Subject: pwm: bcm2835: Fix period_ns range check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The range check for period_ns was written under assumption of a fixed PWM clock. With clk-bcm2835 driver the PWM clock is a dynamic one. So fix this by doing the range check on the period register value. Signed-off-by: Stefan Wahren Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 52763063c100..2c82386c0ebf 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -21,7 +21,7 @@ #define PERIOD(x) (((x) * 0x10) + 0x10) #define DUTY(x) (((x) * 0x10) + 0x14) -#define MIN_PERIOD 108 /* 9.2 MHz max. PWM clock */ +#define PERIOD_MIN 0x2 struct bcm2835_pwm { struct pwm_chip chip; @@ -64,6 +64,7 @@ static int bcm2835_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct bcm2835_pwm *pc = to_bcm2835_pwm(chip); unsigned long rate = clk_get_rate(pc->clk); unsigned long scaler; + u32 period; if (!rate) { dev_err(pc->dev, "failed to get clock rate\n"); @@ -71,14 +72,14 @@ 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); - if (period_ns <= MIN_PERIOD) + if (period < PERIOD_MIN) return -EINVAL; writel(DIV_ROUND_CLOSEST(duty_ns, scaler), pc->base + DUTY(pwm->hwpwm)); - writel(DIV_ROUND_CLOSEST(period_ns, scaler), - pc->base + PERIOD(pwm->hwpwm)); + writel(period, pc->base + PERIOD(pwm->hwpwm)); return 0; } -- cgit v1.2.3 From 9e3ca01f7e58ef4662c18adcb766ee3422ace0fb Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 24 Aug 2019 16:09:48 +0200 Subject: pwm: bcm2835: Suppress error message during deferred probe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This suppresses error messages in case the PWM clock isn't ready yet. Signed-off-by: Stefan Wahren Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-bcm2835.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-bcm2835.c b/drivers/pwm/pwm-bcm2835.c index 2c82386c0ebf..91e24f01b54e 100644 --- a/drivers/pwm/pwm-bcm2835.c +++ b/drivers/pwm/pwm-bcm2835.c @@ -153,8 +153,11 @@ static int bcm2835_pwm_probe(struct platform_device *pdev) pc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pc->clk)) { - dev_err(&pdev->dev, "clock not found: %ld\n", PTR_ERR(pc->clk)); - return PTR_ERR(pc->clk); + ret = PTR_ERR(pc->clk); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "clock not found: %d\n", ret); + + return ret; } ret = clk_prepare_enable(pc->clk); -- cgit v1.2.3 From ba73deb16ff5b2d70b1ffc025c84c1126aad7fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Mon, 2 Sep 2019 16:39:41 +0200 Subject: pwm: rockchip: Set polarity unconditionally in .get_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't rely on *state being zero initialized and PWM_POLARITY_NORMAL being zero. So always assign .polarity. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rockchip.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 51b96cb7dd25..8eb2db59741d 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -90,10 +90,10 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, state->enabled = ((val & enable_conf) == enable_conf) ? true : false; - if (pc->data->supports_polarity) { - if (!(val & PWM_DUTY_POSITIVE)) - state->polarity = PWM_POLARITY_INVERSED; - } + if (pc->data->supports_polarity && !(val & PWM_DUTY_POSITIVE)) + state->polarity = PWM_POLARITY_INVERSED; + else + state->polarity = PWM_POLARITY_NORMAL; clk_disable(pc->pclk); } -- cgit v1.2.3 From fc3c5512e337bdb8b019883ea9078bbccc00c4e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:02 +0200 Subject: pwm: Introduce local struct pwm_chip in pwm_apply_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pwm->chip is dereferenced several times in the pwm_apply_state() function. Introducing a local variable for it helps keeping some lines a bit shorter. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 8edfac17364e..4ab683a30629 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -454,20 +454,23 @@ EXPORT_SYMBOL_GPL(pwm_free); */ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) { + struct pwm_chip *chip; int err; if (!pwm || !state || !state->period || state->duty_cycle > state->period) return -EINVAL; + chip = pwm->chip; + if (state->period == pwm->state.period && state->duty_cycle == pwm->state.duty_cycle && state->polarity == pwm->state.polarity && state->enabled == pwm->state.enabled) return 0; - if (pwm->chip->ops->apply) { - err = pwm->chip->ops->apply(pwm->chip, pwm, state); + if (chip->ops->apply) { + err = chip->ops->apply(chip, pwm, state); if (err) return err; @@ -477,7 +480,7 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) * FIXME: restore the initial state in case of error. */ if (state->polarity != pwm->state.polarity) { - if (!pwm->chip->ops->set_polarity) + if (!chip->ops->set_polarity) return -ENOTSUPP; /* @@ -486,12 +489,12 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) * ->apply(). */ if (pwm->state.enabled) { - pwm->chip->ops->disable(pwm->chip, pwm); + chip->ops->disable(chip, pwm); pwm->state.enabled = false; } - err = pwm->chip->ops->set_polarity(pwm->chip, pwm, - state->polarity); + err = chip->ops->set_polarity(chip, pwm, + state->polarity); if (err) return err; @@ -500,9 +503,9 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) if (state->period != pwm->state.period || state->duty_cycle != pwm->state.duty_cycle) { - err = pwm->chip->ops->config(pwm->chip, pwm, - state->duty_cycle, - state->period); + err = chip->ops->config(pwm->chip, pwm, + state->duty_cycle, + state->period); if (err) return err; @@ -512,11 +515,11 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) if (state->enabled != pwm->state.enabled) { if (state->enabled) { - err = pwm->chip->ops->enable(pwm->chip, pwm); + err = chip->ops->enable(chip, pwm); if (err) return err; } else { - pwm->chip->ops->disable(pwm->chip, pwm); + chip->ops->disable(chip, pwm); } pwm->state.enabled = state->enabled; -- cgit v1.2.3 From 01ccf903edd65f6421612321648fa5a7f4b7cb10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:03 +0200 Subject: pwm: Let pwm_get_state() return the last implemented state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pwm_apply_state() is called the lowlevel driver usually has to apply some rounding because the hardware doesn't support nanosecond resolution. So let pwm_get_state() return the actually implemented state instead of the last applied one if possible. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 4ab683a30629..449ba161877d 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -474,7 +474,14 @@ int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) if (err) return err; - pwm->state = *state; + /* + * .apply might have to round some values in *state, if possible + * read the actually implemented value back. + */ + if (chip->ops->get_state) + chip->ops->get_state(chip, pwm, &pwm->state); + else + pwm->state = *state; } else { /* * FIXME: restore the initial state in case of error. -- cgit v1.2.3 From 797a5ebc26daee5552e668ee4622bc3f47c1f743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:04 +0200 Subject: pwm: rockchip: Don't update the state for the caller of pwm_apply_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pwm-rockchip driver is one of only three PWM drivers which updates the state for the caller of pwm_apply_state(). This might have surprising results if the caller reuses the values expecting them to still represent the same state. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-rockchip.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 8eb2db59741d..83c7627868d8 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -212,12 +212,6 @@ static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, goto out; } - /* - * Update the state with the real hardware, which can differ a bit - * because of period/duty_cycle approximation. - */ - rockchip_pwm_get_state(chip, pwm, state); - out: clk_disable(pc->pclk); -- cgit v1.2.3 From deb9c462f4e539cc7f8389b9855eb7a507c78e7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:05 +0200 Subject: pwm: sun4i: Don't update the state for the caller of pwm_apply_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pwm-sun4i driver is one of only three PWM drivers which updates the state for the caller of pwm_apply_state(). This might have surprising results if the caller reuses the values expecting them to still represent the same state. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-sun4i.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index de78c824bbfd..39007a7c0d83 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -192,12 +192,6 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, *dty = div; *prsclr = prescaler; - div = (u64)pval * NSEC_PER_SEC * *prd; - state->period = DIV_ROUND_CLOSEST_ULL(div, clk_rate); - - div = (u64)pval * NSEC_PER_SEC * *dty; - state->duty_cycle = DIV_ROUND_CLOSEST_ULL(div, clk_rate); - return 0; } -- cgit v1.2.3 From c9675829ba4b0e95c613f6d6d83d2b5cb9c5371c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:06 +0200 Subject: pwm: fsl-ftm: Don't update the state for the caller of pwm_apply_state() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pwm-fsl-ftm driver is one of only three PWM drivers which updates the state for the caller of pwm_apply_state(). This might have surprising results if the caller reuses the values expecting them to still represent the same state. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-fsl-ftm.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 9d31a217111d..3c9738617ceb 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -292,10 +292,6 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc, regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity); - newstate->period = fsl_pwm_ticks_to_ns(fpc, - fpc->period.mod_period + 1); - newstate->duty_cycle = fsl_pwm_ticks_to_ns(fpc, duty); - ftm_set_write_protection(fpc); return 0; -- cgit v1.2.3 From 71523d1812aca61e32e742e87ec064e3d8c615e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sat, 24 Aug 2019 17:37:07 +0200 Subject: pwm: Ensure pwm_apply_state() doesn't modify the state argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is surprising for a PWM consumer when the variable holding the requested state is modified by pwm_apply_state(). Consider for example a driver doing: #define PERIOD 5000000 #define DUTY_LITTLE 10 ... struct pwm_state state = { .period = PERIOD, .duty_cycle = DUTY_LITTLE, .polarity = PWM_POLARITY_NORMAL, .enabled = true, }; pwm_apply_state(mypwm, &state); ... state.duty_cycle = PERIOD / 2; pwm_apply_state(mypwm, &state); For sure the second call to pwm_apply_state() should still have state.period = PERIOD and not something the hardware driver chose for a reason that doesn't necessarily apply to the second call. So declare the state argument as a pointer to a const type and adapt all drivers' .apply callbacks. Signed-off-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/gpio/gpio-mvebu.c | 2 +- drivers/pwm/core.c | 6 ++---- drivers/pwm/pwm-atmel-hlcdc.c | 2 +- drivers/pwm/pwm-atmel.c | 2 +- drivers/pwm/pwm-bcm-iproc.c | 2 +- drivers/pwm/pwm-cros-ec.c | 2 +- drivers/pwm/pwm-fsl-ftm.c | 4 ++-- drivers/pwm/pwm-hibvt.c | 2 +- drivers/pwm/pwm-imx-tpm.c | 4 ++-- drivers/pwm/pwm-imx27.c | 2 +- drivers/pwm/pwm-jz4740.c | 2 +- drivers/pwm/pwm-lpss.c | 2 +- drivers/pwm/pwm-meson.c | 4 ++-- drivers/pwm/pwm-rcar.c | 2 +- drivers/pwm/pwm-rockchip.c | 4 ++-- drivers/pwm/pwm-sifive.c | 2 +- drivers/pwm/pwm-sprd.c | 2 +- drivers/pwm/pwm-stm32-lp.c | 2 +- drivers/pwm/pwm-stm32.c | 4 ++-- drivers/pwm/pwm-sun4i.c | 4 ++-- drivers/pwm/pwm-zx.c | 2 +- 21 files changed, 28 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 869d47f89599..6c0687694341 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -694,7 +694,7 @@ static void mvebu_pwm_get_state(struct pwm_chip *chip, } static int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 449ba161877d..6ad51aa60c03 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -448,11 +448,9 @@ EXPORT_SYMBOL_GPL(pwm_free); /** * pwm_apply_state() - atomically apply a new state to a PWM device * @pwm: PWM device - * @state: new state to apply. This can be adjusted by the PWM driver - * if the requested config is not achievable, for example, - * ->duty_cycle and ->period might be approximated. + * @state: new state to apply */ -int pwm_apply_state(struct pwm_device *pwm, struct pwm_state *state) +int pwm_apply_state(struct pwm_device *pwm, const struct pwm_state *state) { struct pwm_chip *chip; int err; diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index d13a83f430ac..dcbc0489dfd4 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -39,7 +39,7 @@ static inline struct atmel_hlcdc_pwm *to_atmel_hlcdc_pwm(struct pwm_chip *chip) } static int atmel_hlcdc_pwm_apply(struct pwm_chip *c, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct atmel_hlcdc_pwm *chip = to_atmel_hlcdc_pwm(c); struct atmel_hlcdc *hlcdc = chip->hlcdc; diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index e5e1eaf372fa..53bc7b9b3581 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -209,7 +209,7 @@ static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm, } static int atmel_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); struct pwm_state cstate; diff --git a/drivers/pwm/pwm-bcm-iproc.c b/drivers/pwm/pwm-bcm-iproc.c index d961a8207b1c..56c38cfae92c 100644 --- a/drivers/pwm/pwm-bcm-iproc.c +++ b/drivers/pwm/pwm-bcm-iproc.c @@ -115,7 +115,7 @@ static void iproc_pwmc_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } static int iproc_pwmc_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { unsigned long prescale = IPROC_PWM_PRESCALE_MIN; struct iproc_pwmc *ip = to_iproc_pwmc(chip); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 98f6ac6cf6ab..db5faa79c33f 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -93,7 +93,7 @@ static int cros_ec_pwm_get_duty(struct cros_ec_device *ec, u8 index) } static int cros_ec_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct cros_ec_pwm_device *ec_pwm = pwm_to_cros_ec_pwm(chip); int duty_cycle; diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 3c9738617ceb..59272a920479 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -227,7 +227,7 @@ static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc, static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc, struct pwm_device *pwm, - struct pwm_state *newstate) + const struct pwm_state *newstate) { unsigned int duty; u32 reg_polarity; @@ -298,7 +298,7 @@ static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc, } static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *newstate) + const struct pwm_state *newstate) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); struct pwm_state *oldstate = &pwm->state; diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c index 753bd58111e4..ad205fdad372 100644 --- a/drivers/pwm/pwm-hibvt.c +++ b/drivers/pwm/pwm-hibvt.c @@ -149,7 +149,7 @@ static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, } static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); diff --git a/drivers/pwm/pwm-imx-tpm.c b/drivers/pwm/pwm-imx-tpm.c index e8385c1cf342..9145f6160649 100644 --- a/drivers/pwm/pwm-imx-tpm.c +++ b/drivers/pwm/pwm-imx-tpm.c @@ -89,7 +89,7 @@ to_imx_tpm_pwm_chip(struct pwm_chip *chip) static int pwm_imx_tpm_round_state(struct pwm_chip *chip, struct imx_tpm_pwm_param *p, struct pwm_state *real_state, - struct pwm_state *state) + const struct pwm_state *state) { struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); u32 rate, prescale, period_count, clock_unit; @@ -289,7 +289,7 @@ static int pwm_imx_tpm_apply_hw(struct pwm_chip *chip, static int pwm_imx_tpm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct imx_tpm_pwm_chip *tpm = to_imx_tpm_pwm_chip(chip); struct imx_tpm_pwm_param param; diff --git a/drivers/pwm/pwm-imx27.c b/drivers/pwm/pwm-imx27.c index 91c23cbbc167..ae11d8577f18 100644 --- a/drivers/pwm/pwm-imx27.c +++ b/drivers/pwm/pwm-imx27.c @@ -209,7 +209,7 @@ static void pwm_imx27_wait_fifo_slot(struct pwm_chip *chip, } static int pwm_imx27_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { unsigned long period_cycles, duty_cycles, prescale; struct pwm_imx27_chip *imx = to_pwm_imx27_chip(chip); diff --git a/drivers/pwm/pwm-jz4740.c b/drivers/pwm/pwm-jz4740.c index 9d444d012f92..9d78cc21cb12 100644 --- a/drivers/pwm/pwm-jz4740.c +++ b/drivers/pwm/pwm-jz4740.c @@ -88,7 +88,7 @@ static void jz4740_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) } static int jz4740_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct jz4740_pwm_chip *jz4740 = to_jz4740(pwm->chip); unsigned long long tmp; diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c index 4098a4601691..75bbfe5f3bc2 100644 --- a/drivers/pwm/pwm-lpss.c +++ b/drivers/pwm/pwm-lpss.c @@ -122,7 +122,7 @@ static inline void pwm_lpss_cond_enable(struct pwm_device *pwm, bool cond) } static int pwm_lpss_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct pwm_lpss_chip *lpwm = to_lpwm(chip); int ret; diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 3cbff5cbb789..6245bbdb6e6c 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -159,7 +159,7 @@ static void meson_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) } static int meson_pwm_calc(struct meson_pwm *meson, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); unsigned int duty, period, pre_div, cnt, duty_cnt; @@ -265,7 +265,7 @@ static void meson_pwm_disable(struct meson_pwm *meson, struct pwm_device *pwm) } static int meson_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct meson_pwm_channel *channel = pwm_get_chip_data(pwm); struct meson_pwm *meson = to_meson_pwm(chip); diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index c8cd43f91efc..852eb2347954 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -158,7 +158,7 @@ static void rcar_pwm_disable(struct rcar_pwm_chip *rp) } static int rcar_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip); struct pwm_state cur_state; diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 83c7627868d8..73352e6fbccb 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -99,7 +99,7 @@ static void rockchip_pwm_get_state(struct pwm_chip *chip, } static void rockchip_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); unsigned long period, duty; @@ -183,7 +183,7 @@ static int rockchip_pwm_enable(struct pwm_chip *chip, } static int rockchip_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct rockchip_pwm_chip *pc = to_rockchip_pwm_chip(chip); struct pwm_state curstate; diff --git a/drivers/pwm/pwm-sifive.c b/drivers/pwm/pwm-sifive.c index bb4f02ce4f94..cc63f9baa481 100644 --- a/drivers/pwm/pwm-sifive.c +++ b/drivers/pwm/pwm-sifive.c @@ -147,7 +147,7 @@ static int pwm_sifive_enable(struct pwm_chip *chip, bool enable) } static int pwm_sifive_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct pwm_sifive_ddata *ddata = pwm_sifive_chip_to_ddata(chip); struct pwm_state cur_state; diff --git a/drivers/pwm/pwm-sprd.c b/drivers/pwm/pwm-sprd.c index 68c2d9f0411b..be2394227423 100644 --- a/drivers/pwm/pwm-sprd.c +++ b/drivers/pwm/pwm-sprd.c @@ -156,7 +156,7 @@ static int sprd_pwm_config(struct sprd_pwm_chip *spc, struct pwm_device *pwm, } static int sprd_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct sprd_pwm_chip *spc = container_of(chip, struct sprd_pwm_chip, chip); diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 2211a642066d..21cb260dc2c0 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -32,7 +32,7 @@ static inline struct stm32_pwm_lp *to_stm32_pwm_lp(struct pwm_chip *chip) #define STM32_LPTIM_MAX_PRESCALER 128 static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct stm32_pwm_lp *priv = to_stm32_pwm_lp(chip); unsigned long long prd, div, dty; diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c index 740e2dec8313..359b08596d9e 100644 --- a/drivers/pwm/pwm-stm32.c +++ b/drivers/pwm/pwm-stm32.c @@ -440,7 +440,7 @@ static void stm32_pwm_disable(struct stm32_pwm *priv, int ch) } static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { bool enabled; struct stm32_pwm *priv = to_stm32_pwm_dev(chip); @@ -468,7 +468,7 @@ static int stm32_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, } static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct stm32_pwm *priv = to_stm32_pwm_dev(chip); int ret; diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c index 39007a7c0d83..6f5840a1a82d 100644 --- a/drivers/pwm/pwm-sun4i.c +++ b/drivers/pwm/pwm-sun4i.c @@ -145,7 +145,7 @@ static void sun4i_pwm_get_state(struct pwm_chip *chip, } static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, - struct pwm_state *state, + const struct pwm_state *state, u32 *dty, u32 *prd, unsigned int *prsclr) { u64 clk_rate, div = 0; @@ -196,7 +196,7 @@ static int sun4i_pwm_calculate(struct sun4i_pwm_chip *sun4i_pwm, } static int sun4i_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip); struct pwm_state cstate; diff --git a/drivers/pwm/pwm-zx.c b/drivers/pwm/pwm-zx.c index e24f4be35316..e2c21cc34a96 100644 --- a/drivers/pwm/pwm-zx.c +++ b/drivers/pwm/pwm-zx.c @@ -148,7 +148,7 @@ static int zx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, } static int zx_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, - struct pwm_state *state) + const struct pwm_state *state) { struct zx_pwm_chip *zpc = to_zx_pwm_chip(chip); struct pwm_state cstate; -- cgit v1.2.3 From c91e3234c6035baf5a79763cb4fcd5d23ce75c2b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Wed, 18 Sep 2019 16:54:21 +0200 Subject: pwm: stm32-lp: Add check in case requested period cannot be achieved MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LPTimer can use a 32KHz clock for counting. It depends on clock tree configuration. In such a case, PWM output frequency range is limited. Although unlikely, nothing prevents user from requesting a PWM frequency above counting clock (32KHz for instance): - This causes (prd - 1) = 0xffff to be written in ARR register later in the apply() routine. This results in badly configured PWM period (and also duty_cycle). Add a check to report an error is such a case. Signed-off-by: Fabrice Gasnier Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-stm32-lp.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 21cb260dc2c0..67fca62524dc 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -59,6 +59,12 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, /* Calculate the period and prescaler value */ div = (unsigned long long)clk_get_rate(priv->clk) * state->period; do_div(div, NSEC_PER_SEC); + if (!div) { + /* Clock is too slow to achieve requested period. */ + dev_dbg(priv->chip.dev, "Can't reach %u ns\n", state->period); + return -EINVAL; + } + prd = div; while (div > STM32_LPTIM_MAX_ARR) { presc++; -- cgit v1.2.3 From 3d4d85741ad3d880cb432d9121f5563e6a57ff2e Mon Sep 17 00:00:00 2001 From: Kamel Bouhara Date: Wed, 18 Sep 2019 16:57:16 +0200 Subject: pwm: atmel: Remove platform_device_id and use only dt bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 26202873bb51 ("avr32: remove support for AVR32 architecture") there is no more user of platform_device_id and we should only use dt bindings Signed-off-by: Kamel Bouhara Acked-by: Alexandre Belloni Acked-by: Claudiu Beznea Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 2 +- drivers/pwm/pwm-atmel.c | 35 +++-------------------------------- 2 files changed, 4 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 31dfc88ef362..08f35e2b167e 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -44,7 +44,7 @@ config PWM_AB8500 config PWM_ATMEL tristate "Atmel PWM support" - depends on ARCH_AT91 + depends on ARCH_AT91 && OF help Generic PWM framework driver for Atmel SoC. diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 53bc7b9b3581..5b861da3e325 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -318,19 +318,6 @@ static const struct atmel_pwm_data mchp_sam9x60_pwm_data = { }, }; -static const struct platform_device_id atmel_pwm_devtypes[] = { - { - .name = "at91sam9rl-pwm", - .driver_data = (kernel_ulong_t)&atmel_sam9rl_pwm_data, - }, { - .name = "sama5d3-pwm", - .driver_data = (kernel_ulong_t)&atmel_sama5_pwm_data, - }, { - /* sentinel */ - }, -}; -MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes); - static const struct of_device_id atmel_pwm_dt_ids[] = { { .compatible = "atmel,at91sam9rl-pwm", @@ -350,19 +337,6 @@ static const struct of_device_id atmel_pwm_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); -static inline const struct atmel_pwm_data * -atmel_pwm_get_driver_data(struct platform_device *pdev) -{ - const struct platform_device_id *id; - - if (pdev->dev.of_node) - return of_device_get_match_data(&pdev->dev); - - id = platform_get_device_id(pdev); - - return (struct atmel_pwm_data *)id->driver_data; -} - static int atmel_pwm_probe(struct platform_device *pdev) { const struct atmel_pwm_data *data; @@ -370,7 +344,7 @@ static int atmel_pwm_probe(struct platform_device *pdev) struct resource *res; int ret; - data = atmel_pwm_get_driver_data(pdev); + data = of_device_get_match_data(&pdev->dev); if (!data) return -ENODEV; @@ -396,10 +370,8 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.dev = &pdev->dev; atmel_pwm->chip.ops = &atmel_pwm_ops; - if (pdev->dev.of_node) { - atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags; - atmel_pwm->chip.of_pwm_n_cells = 3; - } + atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags; + atmel_pwm->chip.of_pwm_n_cells = 3; atmel_pwm->chip.base = -1; atmel_pwm->chip.npwm = 4; @@ -437,7 +409,6 @@ static struct platform_driver atmel_pwm_driver = { .name = "atmel-pwm", .of_match_table = of_match_ptr(atmel_pwm_dt_ids), }, - .id_table = atmel_pwm_devtypes, .probe = atmel_pwm_probe, .remove = atmel_pwm_remove, }; -- cgit v1.2.3 From d85b9ce198e3689141cce965cb840f1c435ac4d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Sat, 21 Sep 2019 01:55:48 +0200 Subject: pwm: atmel: Remove unneeded check for match data Since the driver is now exclusively DT, it only binds if it finds a match in the of_device_id table. But in that case the associated data can never be NULL, so drop the unnecessary check. While at it, drop the extra local variable and store the pointer to this per-SoC data in the driver data directly. Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 5b861da3e325..2e0b3d985d24 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -339,19 +339,16 @@ MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids); static int atmel_pwm_probe(struct platform_device *pdev) { - const struct atmel_pwm_data *data; struct atmel_pwm_chip *atmel_pwm; struct resource *res; int ret; - data = of_device_get_match_data(&pdev->dev); - if (!data) - return -ENODEV; - atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL); if (!atmel_pwm) return -ENOMEM; + atmel_pwm->data = of_device_get_match_data(&pdev->dev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(atmel_pwm->base)) @@ -375,7 +372,6 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.base = -1; atmel_pwm->chip.npwm = 4; - atmel_pwm->data = data; atmel_pwm->updated_pwms = 0; mutex_init(&atmel_pwm->isr_lock); -- cgit v1.2.3 From 9193c16e5a9899e742a862a0fec9bb5235008370 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Sat, 21 Sep 2019 01:58:58 +0200 Subject: pwm: atmel: Consolidate driver data initialization This helps readability by separating the driver-specific bits from the PWM framework bits. Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index 2e0b3d985d24..9ba733467e26 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -347,7 +347,9 @@ static int atmel_pwm_probe(struct platform_device *pdev) if (!atmel_pwm) return -ENOMEM; + mutex_init(&atmel_pwm->isr_lock); 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); @@ -366,14 +368,10 @@ static int atmel_pwm_probe(struct platform_device *pdev) atmel_pwm->chip.dev = &pdev->dev; atmel_pwm->chip.ops = &atmel_pwm_ops; - atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags; atmel_pwm->chip.of_pwm_n_cells = 3; - atmel_pwm->chip.base = -1; atmel_pwm->chip.npwm = 4; - atmel_pwm->updated_pwms = 0; - mutex_init(&atmel_pwm->isr_lock); ret = pwmchip_add(&atmel_pwm->chip); if (ret < 0) { -- cgit v1.2.3 From e6c7c258f035ffec9d8a808c1bc34b6a5beae0ef Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 20 Sep 2019 06:49:02 +0800 Subject: pwm: mediatek: Drop the check for of_device_get_match_data() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch drop the check for of_device_get_match_data. Due to the only way call driver probe is compatible match. The data pointer which points to the SoC specify data is directly set by driver, and it should not be NULL in our case. We can safety remove the check for the result of of_device_get_match_data(). Signed-off-by: Ryder Lee Signed-off-by: Sam Shih Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6697e30811e7..459b2ccd0b75 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -226,7 +226,6 @@ static const struct pwm_ops mtk_pwm_ops = { static int mtk_pwm_probe(struct platform_device *pdev) { - const struct mtk_pwm_platform_data *data; struct mtk_pwm_chip *pc; struct resource *res; unsigned int i; @@ -236,17 +235,14 @@ static int mtk_pwm_probe(struct platform_device *pdev) if (!pc) return -ENOMEM; - data = of_device_get_match_data(&pdev->dev); - if (data == NULL) - return -EINVAL; - pc->soc = data; + 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); if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - for (i = 0; i < data->num_pwms + 2 && pc->soc->has_clks; i++) { + for (i = 0; i < pc->soc->num_pwms + 2 && pc->soc->has_clks; i++) { pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); if (IS_ERR(pc->clks[i])) { dev_err(&pdev->dev, "clock: %s fail: %ld\n", @@ -260,7 +256,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) pc->chip.dev = &pdev->dev; pc->chip.ops = &mtk_pwm_ops; pc->chip.base = -1; - pc->chip.npwm = data->num_pwms; + pc->chip.npwm = pc->soc->num_pwms; ret = pwmchip_add(&pc->chip); if (ret < 0) { -- cgit v1.2.3 From 61aa258ab1a50b834267f5df6cabef0d10f8955a Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 20 Sep 2019 06:49:03 +0800 Subject: pwm: mediatek: Remove the has_clks field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can use fixed clocks to repair mt7628 PWM during configure from userspace. The SoC is legacy MIPS and has no complex clock tree. Because we can get the clock frequency for period calculation from fixed clocks specified in DT, we can remove the has_clock field, and directly use devm_clk_get() and clk_get_rate(). Signed-off-by: Ryder Lee Signed-off-by: Sam Shih Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 459b2ccd0b75..9394735b0762 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -57,7 +57,6 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { struct mtk_pwm_platform_data { unsigned int num_pwms; bool pwm45_fixup; - bool has_clks; }; /** @@ -87,9 +86,6 @@ static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); int ret; - if (!pc->soc->has_clks) - return 0; - ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]); if (ret < 0) return ret; @@ -116,9 +112,6 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); - if (!pc->soc->has_clks) - return; - clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); @@ -242,7 +235,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - for (i = 0; i < pc->soc->num_pwms + 2 && pc->soc->has_clks; i++) { + for (i = 0; i < pc->soc->num_pwms + 2; i++) { pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); if (IS_ERR(pc->clks[i])) { dev_err(&pdev->dev, "clock: %s fail: %ld\n", @@ -277,31 +270,26 @@ static int mtk_pwm_remove(struct platform_device *pdev) static const struct mtk_pwm_platform_data mt2712_pwm_data = { .num_pwms = 8, .pwm45_fixup = false, - .has_clks = true, }; static const struct mtk_pwm_platform_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, - .has_clks = true, }; static const struct mtk_pwm_platform_data mt7623_pwm_data = { .num_pwms = 5, .pwm45_fixup = true, - .has_clks = true, }; static const struct mtk_pwm_platform_data mt7628_pwm_data = { .num_pwms = 4, .pwm45_fixup = true, - .has_clks = false, }; static const struct mtk_pwm_platform_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, - .has_clks = true, }; static const struct of_device_id mtk_pwm_of_match[] = { -- cgit v1.2.3 From efecdeb82f21d4100566ce85bda2d7ffb9c9edff Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 20 Sep 2019 06:49:04 +0800 Subject: pwm: mediatek: Allocate the clks array dynamically MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using fixed size of arrays, allocate the memory for them based on the number of PWMs specified for each SoC generation. Signed-off-by: Ryder Lee Signed-off-by: Sam Shih Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 79 ++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 9394735b0762..db986b77e556 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -35,25 +35,6 @@ #define PWM_CLK_DIV_MAX 7 -enum { - MTK_CLK_MAIN = 0, - MTK_CLK_TOP, - MTK_CLK_PWM1, - MTK_CLK_PWM2, - MTK_CLK_PWM3, - MTK_CLK_PWM4, - MTK_CLK_PWM5, - MTK_CLK_PWM6, - MTK_CLK_PWM7, - MTK_CLK_PWM8, - MTK_CLK_MAX, -}; - -static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { - "main", "top", "pwm1", "pwm2", "pwm3", "pwm4", "pwm5", "pwm6", "pwm7", - "pwm8" -}; - struct mtk_pwm_platform_data { unsigned int num_pwms; bool pwm45_fixup; @@ -63,12 +44,17 @@ struct mtk_pwm_platform_data { * struct mtk_pwm_chip - struct representing PWM chip * @chip: linux PWM chip representation * @regs: base address of PWM chip - * @clks: list of clocks + * @clk_top: the top clock generator + * @clk_main: the clock used by PWM core + * @clk_pwms: the clock used by each PWM channel + * @clk_freq: the fix clock frequency of legacy MIPS SoC */ struct mtk_pwm_chip { struct pwm_chip chip; void __iomem *regs; - struct clk *clks[MTK_CLK_MAX]; + struct clk *clk_top; + struct clk *clk_main; + struct clk **clk_pwms; const struct mtk_pwm_platform_data *soc; }; @@ -86,24 +72,24 @@ static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); int ret; - ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]); + ret = clk_prepare_enable(pc->clk_top); if (ret < 0) return ret; - ret = clk_prepare_enable(pc->clks[MTK_CLK_MAIN]); + ret = clk_prepare_enable(pc->clk_main); if (ret < 0) goto disable_clk_top; - ret = clk_prepare_enable(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); + ret = clk_prepare_enable(pc->clk_pwms[pwm->hwpwm]); if (ret < 0) goto disable_clk_main; return 0; disable_clk_main: - clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); + clk_disable_unprepare(pc->clk_main); disable_clk_top: - clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); + clk_disable_unprepare(pc->clk_top); return ret; } @@ -112,9 +98,9 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); - clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); - clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); - clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); + clk_disable_unprepare(pc->clk_pwms[pwm->hwpwm]); + clk_disable_unprepare(pc->clk_main); + clk_disable_unprepare(pc->clk_top); } static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, @@ -134,7 +120,7 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); - struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; + struct clk *clk = pc->clk_pwms[pwm->hwpwm]; u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH, reg_thres = PWMTHRES; u64 resolution; @@ -235,12 +221,35 @@ static int mtk_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - for (i = 0; i < pc->soc->num_pwms + 2; i++) { - pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); - if (IS_ERR(pc->clks[i])) { + pc->clk_pwms = devm_kcalloc(&pdev->dev, pc->soc->num_pwms, + sizeof(*pc->clk_pwms), GFP_KERNEL); + if (!pc->clk_pwms) + return -ENOMEM; + + pc->clk_top = devm_clk_get(&pdev->dev, "top"); + if (IS_ERR(pc->clk_top)) { + dev_err(&pdev->dev, "clock: top fail: %ld\n", + PTR_ERR(pc->clk_top)); + return PTR_ERR(pc->clk_top); + } + + pc->clk_main = devm_clk_get(&pdev->dev, "main"); + if (IS_ERR(pc->clk_main)) { + dev_err(&pdev->dev, "clock: main fail: %ld\n", + PTR_ERR(pc->clk_main)); + return PTR_ERR(pc->clk_main); + } + + for (i = 0; i < pc->soc->num_pwms; i++) { + char name[8]; + + snprintf(name, sizeof(name), "pwm%d", i + 1); + + pc->clk_pwms[i] = devm_clk_get(&pdev->dev, name); + if (IS_ERR(pc->clk_pwms[i])) { dev_err(&pdev->dev, "clock: %s fail: %ld\n", - mtk_pwm_clk_name[i], PTR_ERR(pc->clks[i])); - return PTR_ERR(pc->clks[i]); + name, PTR_ERR(pc->clk_pwms[i])); + return PTR_ERR(pc->clk_pwms[i]); } } -- cgit v1.2.3 From 2503781c97fa66f1ee7ffac21f8c5c330b82b5eb Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 20 Sep 2019 06:49:05 +0800 Subject: pwm: mediatek: Use pwm_mediatek as common prefix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use pwm_mediatek as common prefix to match the filename. No functional change intended. Signed-off-by: Ryder Lee Signed-off-by: Sam Shih Acked-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 117 +++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index db986b77e556..6b9a5857b5b6 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -35,13 +35,13 @@ #define PWM_CLK_DIV_MAX 7 -struct mtk_pwm_platform_data { +struct pwm_mediatek_of_data { unsigned int num_pwms; bool pwm45_fixup; }; /** - * struct mtk_pwm_chip - struct representing PWM chip + * struct pwm_mediatek_chip - struct representing PWM chip * @chip: linux PWM chip representation * @regs: base address of PWM chip * @clk_top: the top clock generator @@ -49,27 +49,29 @@ struct mtk_pwm_platform_data { * @clk_pwms: the clock used by each PWM channel * @clk_freq: the fix clock frequency of legacy MIPS SoC */ -struct mtk_pwm_chip { +struct pwm_mediatek_chip { struct pwm_chip chip; void __iomem *regs; struct clk *clk_top; struct clk *clk_main; struct clk **clk_pwms; - const struct mtk_pwm_platform_data *soc; + const struct pwm_mediatek_of_data *soc; }; -static const unsigned int mtk_pwm_reg_offset[] = { +static const unsigned int pwm_mediatek_reg_offset[] = { 0x0010, 0x0050, 0x0090, 0x00d0, 0x0110, 0x0150, 0x0190, 0x0220 }; -static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) +static inline struct pwm_mediatek_chip * +to_pwm_mediatek_chip(struct pwm_chip *chip) { - return container_of(chip, struct mtk_pwm_chip, chip); + return container_of(chip, struct pwm_mediatek_chip, chip); } -static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int pwm_mediatek_clk_enable(struct pwm_chip *chip, + struct pwm_device *pwm) { - struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); int ret; ret = clk_prepare_enable(pc->clk_top); @@ -94,45 +96,46 @@ disable_clk_top: return ret; } -static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) +static void pwm_mediatek_clk_disable(struct pwm_chip *chip, + struct pwm_device *pwm) { - struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); clk_disable_unprepare(pc->clk_pwms[pwm->hwpwm]); clk_disable_unprepare(pc->clk_main); clk_disable_unprepare(pc->clk_top); } -static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, - unsigned int offset) +static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip, + unsigned int num, unsigned int offset) { - return readl(chip->regs + mtk_pwm_reg_offset[num] + offset); + return readl(chip->regs + pwm_mediatek_reg_offset[num] + offset); } -static inline void mtk_pwm_writel(struct mtk_pwm_chip *chip, - unsigned int num, unsigned int offset, - u32 value) +static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip, + unsigned int num, unsigned int offset, + u32 value) { - writel(value, chip->regs + mtk_pwm_reg_offset[num] + offset); + writel(value, chip->regs + pwm_mediatek_reg_offset[num] + offset); } -static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, - int duty_ns, int period_ns) +static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) { - struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); - struct clk *clk = pc->clk_pwms[pwm->hwpwm]; + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH, reg_thres = PWMTHRES; u64 resolution; int ret; - ret = mtk_pwm_clk_enable(chip, pwm); + ret = pwm_mediatek_clk_enable(chip, pwm); + if (ret < 0) return ret; /* Using resolution in picosecond gets accuracy higher */ resolution = (u64)NSEC_PER_SEC * 1000; - do_div(resolution, clk_get_rate(clk)); + do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm])); cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution); while (cnt_period > 8191) { @@ -143,7 +146,7 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, } if (clkdiv > PWM_CLK_DIV_MAX) { - mtk_pwm_clk_disable(chip, pwm); + pwm_mediatek_clk_disable(chip, pwm); dev_err(chip->dev, "period %d not supported\n", period_ns); return -EINVAL; } @@ -158,22 +161,22 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, } cnt_duty = DIV_ROUND_CLOSEST_ULL((u64)duty_ns * 1000, resolution); - mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); - mtk_pwm_writel(pc, pwm->hwpwm, reg_width, cnt_period); - mtk_pwm_writel(pc, pwm->hwpwm, reg_thres, cnt_duty); + pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); + pwm_mediatek_writel(pc, pwm->hwpwm, reg_width, cnt_period); + pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty); - mtk_pwm_clk_disable(chip, pwm); + pwm_mediatek_clk_disable(chip, pwm); return 0; } -static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +static int pwm_mediatek_enable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); u32 value; int ret; - ret = mtk_pwm_clk_enable(chip, pwm); + ret = pwm_mediatek_clk_enable(chip, pwm); if (ret < 0) return ret; @@ -184,28 +187,28 @@ static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return 0; } -static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +static void pwm_mediatek_disable(struct pwm_chip *chip, struct pwm_device *pwm) { - struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip); u32 value; value = readl(pc->regs); value &= ~BIT(pwm->hwpwm); writel(value, pc->regs); - mtk_pwm_clk_disable(chip, pwm); + pwm_mediatek_clk_disable(chip, pwm); } -static const struct pwm_ops mtk_pwm_ops = { - .config = mtk_pwm_config, - .enable = mtk_pwm_enable, - .disable = mtk_pwm_disable, +static const struct pwm_ops pwm_mediatek_ops = { + .config = pwm_mediatek_config, + .enable = pwm_mediatek_enable, + .disable = pwm_mediatek_disable, .owner = THIS_MODULE, }; -static int mtk_pwm_probe(struct platform_device *pdev) +static int pwm_mediatek_probe(struct platform_device *pdev) { - struct mtk_pwm_chip *pc; + struct pwm_mediatek_chip *pc; struct resource *res; unsigned int i; int ret; @@ -256,7 +259,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) platform_set_drvdata(pdev, pc); pc->chip.dev = &pdev->dev; - pc->chip.ops = &mtk_pwm_ops; + pc->chip.ops = &pwm_mediatek_ops; pc->chip.base = -1; pc->chip.npwm = pc->soc->num_pwms; @@ -269,39 +272,39 @@ static int mtk_pwm_probe(struct platform_device *pdev) return 0; } -static int mtk_pwm_remove(struct platform_device *pdev) +static int pwm_mediatek_remove(struct platform_device *pdev) { - struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); + struct pwm_mediatek_chip *pc = platform_get_drvdata(pdev); return pwmchip_remove(&pc->chip); } -static const struct mtk_pwm_platform_data mt2712_pwm_data = { +static const struct pwm_mediatek_of_data mt2712_pwm_data = { .num_pwms = 8, .pwm45_fixup = false, }; -static const struct mtk_pwm_platform_data mt7622_pwm_data = { +static const struct pwm_mediatek_of_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, }; -static const struct mtk_pwm_platform_data mt7623_pwm_data = { +static const struct pwm_mediatek_of_data mt7623_pwm_data = { .num_pwms = 5, .pwm45_fixup = true, }; -static const struct mtk_pwm_platform_data mt7628_pwm_data = { +static const struct pwm_mediatek_of_data mt7628_pwm_data = { .num_pwms = 4, .pwm45_fixup = true, }; -static const struct mtk_pwm_platform_data mt8516_pwm_data = { +static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, }; -static const struct of_device_id mtk_pwm_of_match[] = { +static const struct of_device_id pwm_mediatek_of_match[] = { { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, @@ -309,17 +312,17 @@ static const struct of_device_id mtk_pwm_of_match[] = { { .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data }, { }, }; -MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); +MODULE_DEVICE_TABLE(of, pwm_mediatek_of_match); -static struct platform_driver mtk_pwm_driver = { +static struct platform_driver pwm_mediatek_driver = { .driver = { - .name = "mtk-pwm", - .of_match_table = mtk_pwm_of_match, + .name = "pwm-mediatek", + .of_match_table = pwm_mediatek_of_match, }, - .probe = mtk_pwm_probe, - .remove = mtk_pwm_remove, + .probe = pwm_mediatek_probe, + .remove = pwm_mediatek_remove, }; -module_platform_driver(mtk_pwm_driver); +module_platform_driver(pwm_mediatek_driver); MODULE_AUTHOR("John Crispin "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4bea6dd5be7e2ab8c2368ee9724ef88793b2421b Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Fri, 20 Sep 2019 06:49:06 +0800 Subject: pwm: mediatek: Update license and switch to SPDX tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add SPDX identifiers to pwm-mediatek.c. Update MODULE_LICENSE to correctly reflect the GNU General Public License v2.0. Signed-off-by: Ryder Lee Signed-off-by: Sam Shih Reviewed-by: Uwe Kleine-König Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 6b9a5857b5b6..7782fadbc116 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -1,12 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Mediatek Pulse Width Modulator driver + * MediaTek Pulse Width Modulator driver * * Copyright (C) 2015 John Crispin * Copyright (C) 2017 Zhi Mao * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. */ #include @@ -325,4 +323,4 @@ static struct platform_driver pwm_mediatek_driver = { module_platform_driver(pwm_mediatek_driver); MODULE_AUTHOR("John Crispin "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 715d14da670e353c8c827f97e61ba00969929e33 Mon Sep 17 00:00:00 2001 From: Sam Shih Date: Wed, 25 Sep 2019 22:32:33 +0800 Subject: pwm: mediatek: Add MT7629 compatible string This adds pwm support for MT7629, and separate mt7629 compatible string from mt7622 Signed-off-by: Sam Shih Signed-off-by: Thierry Reding --- drivers/pwm/pwm-mediatek.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 7782fadbc116..b94e0d09c300 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -297,6 +297,11 @@ static const struct pwm_mediatek_of_data mt7628_pwm_data = { .pwm45_fixup = true, }; +static const struct pwm_mediatek_of_data mt7629_pwm_data = { + .num_pwms = 1, + .pwm45_fixup = false, +}; + static const struct pwm_mediatek_of_data mt8516_pwm_data = { .num_pwms = 5, .pwm45_fixup = false, @@ -307,6 +312,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = { { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, { .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,mt8516-pwm", .data = &mt8516_pwm_data }, { }, }; -- cgit v1.2.3