diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-11 13:04:32 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-09-11 13:04:32 -0700 |
commit | 66c9457df3926efff65529dab1a8c742df756790 (patch) | |
tree | bdc22614d6c891cf08da1b08bc336504827168e8 /drivers/pwm/pwm-mediatek.c | |
parent | 669bf77a543b4a30d82a376bb9fc0c02da513303 (diff) | |
parent | 7755daf5e7e82499a4cdd7c2ad2be2578cc1df20 (diff) | |
download | op-kernel-dev-66c9457df3926efff65529dab1a8c742df756790.zip op-kernel-dev-66c9457df3926efff65529dab1a8c742df756790.tar.gz |
Merge tag 'pwm/for-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm
Pull pwm updates from Thierry Reding:
"The changes for this release include a new driver for the PWM
controller found on SoCs of the ZTX ZX family. Support for an old
SH-Mobile SoC has been dropped and the Rockchip and MediaTek drivers
gain support for more generations.
Other than that there are a bunch of coding style fixes, minor bug
fixes and cleanup as well as documentation patches"
* tag 'pwm/for-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thierry.reding/linux-pwm: (32 commits)
pwm: pwm-samsung: fix suspend/resume support
pwm: samsung: Remove redundant checks from pwm_samsung_config()
pwm: mediatek: Disable clock on PWM configuration failure
dt-bindings: pwm: Add MT2712/MT7622 information
pwm: mediatek: Fix clock control issue
pwm: mediatek: Fix PWM source clock selection
pwm: mediatek: Fix Kconfig description
pwm: tegra: Explicitly request exclusive reset control
pwm: hibvt: Explicitly request exclusive reset control
pwm: tiehrpwm: Set driver data before runtime PM enable
pwm: tiehrpwm: Miscellaneous coding style fixups
pwm: tiecap: Set driver data before runtime PM enable
pwm: tiecap: Miscellaneous coding style fixups
dt-bindings: pwm: tiecap: Add TI 66AK2G SoC specific compatible
pwm: tiehrpwm: fix clock imbalance in probe error path
pwm: tiehrpwm: Fix runtime PM imbalance at unbind
pwm: Kconfig: Enable pwm-tiecap to be built for Keystone
pwm: Add ZTE ZX PWM device driver
dt-bindings: pwm: Add bindings doc for ZTE ZX PWM controller
pwm: bcm2835: Support for polarity setting via DT
...
Diffstat (limited to 'drivers/pwm/pwm-mediatek.c')
-rw-r--r-- | drivers/pwm/pwm-mediatek.c | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 5c11bc7..b52f3af 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -2,6 +2,7 @@ * Mediatek Pulse Width Modulator driver * * Copyright (C) 2015 John Crispin <blogic@openwrt.org> + * Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com> * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -29,6 +30,8 @@ #define PWMDWIDTH 0x2c #define PWMTHRES 0x30 +#define PWM_CLK_DIV_MAX 7 + enum { MTK_CLK_MAIN = 0, MTK_CLK_TOP, @@ -61,6 +64,42 @@ static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct mtk_pwm_chip, chip); } +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]); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(pc->clks[MTK_CLK_MAIN]); + if (ret < 0) + goto disable_clk_top; + + ret = clk_prepare_enable(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); + if (ret < 0) + goto disable_clk_main; + + return 0; + +disable_clk_main: + clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); +disable_clk_top: + clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); + + return ret; +} + +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]); +} + static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, unsigned int offset) { @@ -80,6 +119,11 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; u32 resolution, clkdiv = 0; + int ret; + + ret = mtk_pwm_clk_enable(chip, pwm); + if (ret < 0) + return ret; resolution = NSEC_PER_SEC / clk_get_rate(clk); @@ -88,13 +132,18 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, clkdiv++; } - if (clkdiv > 7) + if (clkdiv > PWM_CLK_DIV_MAX) { + mtk_pwm_clk_disable(chip, pwm); + dev_err(chip->dev, "period %d not supported\n", period_ns); return -EINVAL; + } - mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) | clkdiv); + mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); + mtk_pwm_clk_disable(chip, pwm); + return 0; } @@ -104,7 +153,7 @@ static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) u32 value; int ret; - ret = clk_prepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); + ret = mtk_pwm_clk_enable(chip, pwm); if (ret < 0) return ret; @@ -124,7 +173,7 @@ static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) value &= ~BIT(pwm->hwpwm); writel(value, pc->regs); - clk_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); + mtk_pwm_clk_disable(chip, pwm); } static const struct pwm_ops mtk_pwm_ops = { @@ -156,14 +205,6 @@ static int mtk_pwm_probe(struct platform_device *pdev) return PTR_ERR(pc->clks[i]); } - ret = clk_prepare(pc->clks[MTK_CLK_TOP]); - if (ret < 0) - return ret; - - ret = clk_prepare(pc->clks[MTK_CLK_MAIN]); - if (ret < 0) - goto disable_clk_top; - platform_set_drvdata(pdev, pc); pc->chip.dev = &pdev->dev; @@ -174,26 +215,15 @@ static int mtk_pwm_probe(struct platform_device *pdev) ret = pwmchip_add(&pc->chip); if (ret < 0) { dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); - goto disable_clk_main; + return ret; } return 0; - -disable_clk_main: - clk_unprepare(pc->clks[MTK_CLK_MAIN]); -disable_clk_top: - clk_unprepare(pc->clks[MTK_CLK_TOP]); - - return ret; } static int mtk_pwm_remove(struct platform_device *pdev) { struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); - unsigned int i; - - for (i = 0; i < pc->chip.npwm; i++) - pwm_disable(&pc->chip.pwms[i]); return pwmchip_remove(&pc->chip); } |