aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-mediatek.c
diff options
context:
space:
mode:
authorZhi Mao <zhi.mao@mediatek.com>2017-06-30 02:05:18 -0400
committerThierry Reding <thierry.reding@gmail.com>2017-08-21 04:39:09 -0400
commite7c197ec97c3ac3ed3698be7a21d51a338582e1d (patch)
treee415c1bd31064ae802eb4b92d4a3b3f3cf9a204b /drivers/pwm/pwm-mediatek.c
parentcd30798a6c17c1fa182e9b0bb85bd973776ff193 (diff)
pwm: mediatek: Fix clock control issue
In order to save some power, do not prepare the top and main clocks during mtk_pwm_probe(). Instead, prepare the clocks only when necessary and also make sure to enable the clocks to match the semantics of the common clock framework. While at it, don't explicitly disable all PWM channels in ->remove() because all users should have done that already. Signed-off-by: Zhi Mao <zhi.mao@mediatek.com> Acked-by: John Crispin <john@phrozen.org> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-mediatek.c')
-rw-r--r--drivers/pwm/pwm-mediatek.c69
1 files changed, 47 insertions, 22 deletions
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index d08b5b3dca71..637045998318 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -2,6 +2,7 @@
2 * Mediatek Pulse Width Modulator driver 2 * Mediatek Pulse Width Modulator driver
3 * 3 *
4 * Copyright (C) 2015 John Crispin <blogic@openwrt.org> 4 * Copyright (C) 2015 John Crispin <blogic@openwrt.org>
5 * Copyright (C) 2017 Zhi Mao <zhi.mao@mediatek.com>
5 * 6 *
6 * This file is licensed under the terms of the GNU General Public 7 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any 8 * License version 2. This program is licensed "as is" without any
@@ -61,6 +62,42 @@ static inline struct mtk_pwm_chip *to_mtk_pwm_chip(struct pwm_chip *chip)
61 return container_of(chip, struct mtk_pwm_chip, chip); 62 return container_of(chip, struct mtk_pwm_chip, chip);
62} 63}
63 64
65static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm)
66{
67 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
68 int ret;
69
70 ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]);
71 if (ret < 0)
72 return ret;
73
74 ret = clk_prepare_enable(pc->clks[MTK_CLK_MAIN]);
75 if (ret < 0)
76 goto disable_clk_top;
77
78 ret = clk_prepare_enable(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]);
79 if (ret < 0)
80 goto disable_clk_main;
81
82 return 0;
83
84disable_clk_main:
85 clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]);
86disable_clk_top:
87 clk_disable_unprepare(pc->clks[MTK_CLK_TOP]);
88
89 return ret;
90}
91
92static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm)
93{
94 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
95
96 clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]);
97 clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]);
98 clk_disable_unprepare(pc->clks[MTK_CLK_TOP]);
99}
100
64static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num, 101static inline u32 mtk_pwm_readl(struct mtk_pwm_chip *chip, unsigned int num,
65 unsigned int offset) 102 unsigned int offset)
66{ 103{
@@ -80,6 +117,11 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
80 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 117 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
81 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; 118 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm];
82 u32 resolution, clkdiv = 0; 119 u32 resolution, clkdiv = 0;
120 int ret;
121
122 ret = mtk_pwm_clk_enable(chip, pwm);
123 if (ret < 0)
124 return ret;
83 125
84 resolution = NSEC_PER_SEC / clk_get_rate(clk); 126 resolution = NSEC_PER_SEC / clk_get_rate(clk);
85 127
@@ -95,6 +137,8 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
95 mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); 137 mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution);
96 mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); 138 mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution);
97 139
140 mtk_pwm_clk_disable(chip, pwm);
141
98 return 0; 142 return 0;
99} 143}
100 144
@@ -104,7 +148,7 @@ static int mtk_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
104 u32 value; 148 u32 value;
105 int ret; 149 int ret;
106 150
107 ret = clk_prepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); 151 ret = mtk_pwm_clk_enable(chip, pwm);
108 if (ret < 0) 152 if (ret < 0)
109 return ret; 153 return ret;
110 154
@@ -124,7 +168,7 @@ static void mtk_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
124 value &= ~BIT(pwm->hwpwm); 168 value &= ~BIT(pwm->hwpwm);
125 writel(value, pc->regs); 169 writel(value, pc->regs);
126 170
127 clk_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); 171 mtk_pwm_clk_disable(chip, pwm);
128} 172}
129 173
130static const struct pwm_ops mtk_pwm_ops = { 174static const struct pwm_ops mtk_pwm_ops = {
@@ -156,14 +200,6 @@ static int mtk_pwm_probe(struct platform_device *pdev)
156 return PTR_ERR(pc->clks[i]); 200 return PTR_ERR(pc->clks[i]);
157 } 201 }
158 202
159 ret = clk_prepare(pc->clks[MTK_CLK_TOP]);
160 if (ret < 0)
161 return ret;
162
163 ret = clk_prepare(pc->clks[MTK_CLK_MAIN]);
164 if (ret < 0)
165 goto disable_clk_top;
166
167 platform_set_drvdata(pdev, pc); 203 platform_set_drvdata(pdev, pc);
168 204
169 pc->chip.dev = &pdev->dev; 205 pc->chip.dev = &pdev->dev;
@@ -174,26 +210,15 @@ static int mtk_pwm_probe(struct platform_device *pdev)
174 ret = pwmchip_add(&pc->chip); 210 ret = pwmchip_add(&pc->chip);
175 if (ret < 0) { 211 if (ret < 0) {
176 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); 212 dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
177 goto disable_clk_main; 213 return ret;
178 } 214 }
179 215
180 return 0; 216 return 0;
181
182disable_clk_main:
183 clk_unprepare(pc->clks[MTK_CLK_MAIN]);
184disable_clk_top:
185 clk_unprepare(pc->clks[MTK_CLK_TOP]);
186
187 return ret;
188} 217}
189 218
190static int mtk_pwm_remove(struct platform_device *pdev) 219static int mtk_pwm_remove(struct platform_device *pdev)
191{ 220{
192 struct mtk_pwm_chip *pc = platform_get_drvdata(pdev); 221 struct mtk_pwm_chip *pc = platform_get_drvdata(pdev);
193 unsigned int i;
194
195 for (i = 0; i < pc->chip.npwm; i++)
196 pwm_disable(&pc->chip.pwms[i]);
197 222
198 return pwmchip_remove(&pc->chip); 223 return pwmchip_remove(&pc->chip);
199} 224}