aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pwm/pwm-mediatek.c
diff options
context:
space:
mode:
authorSean Wang <sean.wang@mediatek.com>2018-03-01 03:19:12 -0500
committerThierry Reding <thierry.reding@gmail.com>2018-03-27 18:29:58 -0400
commit360cc036563db27881ce08049f69138438f2ddd0 (patch)
tree3a40b0dd75296e71c2743612fc49c9a07a2f3c9d /drivers/pwm/pwm-mediatek.c
parentb419006275dbc05d73c5659b62c635b47a410a19 (diff)
pwm: mediatek: Fix up PWM4 and PWM5 malfunction on MT7623
Since the offset for both registers, PWMDWIDTH and PWMTHRES, used to control PWM4 or PWM5 are distinct from the other PWMs, whose wrong programming on PWM hardware causes waveform cannot be output as expected. Thus, the patch adds the extra condition for fixing up the weird case to let PWM4 or PWM5 able to work on MT7623. v1 -> v2: use pwm45_fixup naming instead of pwm45_quirk v2 -> v3: add more tags for Reviewed-by, Fixes, and Cc stable Cc: stable@vger.kernel.org Fixes: caf065f8fd58 ("pwm: Add MediaTek PWM support") Signed-off-by: Sean Wang <sean.wang@mediatek.com> Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com> Cc: Zhi Mao <zhi.mao@mediatek.com> Cc: John Crispin <john@phrozen.org> Cc: Matthias Brugger <matthias.bgg@gmail.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
Diffstat (limited to 'drivers/pwm/pwm-mediatek.c')
-rw-r--r--drivers/pwm/pwm-mediatek.c24
1 files changed, 21 insertions, 3 deletions
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index f5d97e0ad52b..796baea7e8fe 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -29,7 +29,9 @@
29#define PWMGDUR 0x0c 29#define PWMGDUR 0x0c
30#define PWMWAVENUM 0x28 30#define PWMWAVENUM 0x28
31#define PWMDWIDTH 0x2c 31#define PWMDWIDTH 0x2c
32#define PWM45DWIDTH_FIXUP 0x30
32#define PWMTHRES 0x30 33#define PWMTHRES 0x30
34#define PWM45THRES_FIXUP 0x34
33 35
34#define PWM_CLK_DIV_MAX 7 36#define PWM_CLK_DIV_MAX 7
35 37
@@ -54,6 +56,7 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = {
54 56
55struct mtk_pwm_platform_data { 57struct mtk_pwm_platform_data {
56 unsigned int num_pwms; 58 unsigned int num_pwms;
59 bool pwm45_fixup;
57}; 60};
58 61
59/** 62/**
@@ -66,6 +69,7 @@ struct mtk_pwm_chip {
66 struct pwm_chip chip; 69 struct pwm_chip chip;
67 void __iomem *regs; 70 void __iomem *regs;
68 struct clk *clks[MTK_CLK_MAX]; 71 struct clk *clks[MTK_CLK_MAX];
72 const struct mtk_pwm_platform_data *soc;
69}; 73};
70 74
71static const unsigned int mtk_pwm_reg_offset[] = { 75static const unsigned int mtk_pwm_reg_offset[] = {
@@ -131,7 +135,8 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
131{ 135{
132 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); 136 struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip);
133 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]; 137 struct clk *clk = pc->clks[MTK_CLK_PWM1 + pwm->hwpwm];
134 u32 resolution, clkdiv = 0; 138 u32 resolution, clkdiv = 0, reg_width = PWMDWIDTH,
139 reg_thres = PWMTHRES;
135 int ret; 140 int ret;
136 141
137 ret = mtk_pwm_clk_enable(chip, pwm); 142 ret = mtk_pwm_clk_enable(chip, pwm);
@@ -151,9 +156,18 @@ static int mtk_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
151 return -EINVAL; 156 return -EINVAL;
152 } 157 }
153 158
159 if (pc->soc->pwm45_fixup && pwm->hwpwm > 2) {
160 /*
161 * PWM[4,5] has distinct offset for PWMDWIDTH and PWMTHRES
162 * from the other PWMs on MT7623.
163 */
164 reg_width = PWM45DWIDTH_FIXUP;
165 reg_thres = PWM45THRES_FIXUP;
166 }
167
154 mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv); 168 mtk_pwm_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv);
155 mtk_pwm_writel(pc, pwm->hwpwm, PWMDWIDTH, period_ns / resolution); 169 mtk_pwm_writel(pc, pwm->hwpwm, reg_width, period_ns / resolution);
156 mtk_pwm_writel(pc, pwm->hwpwm, PWMTHRES, duty_ns / resolution); 170 mtk_pwm_writel(pc, pwm->hwpwm, reg_thres, duty_ns / resolution);
157 171
158 mtk_pwm_clk_disable(chip, pwm); 172 mtk_pwm_clk_disable(chip, pwm);
159 173
@@ -211,6 +225,7 @@ static int mtk_pwm_probe(struct platform_device *pdev)
211 data = of_device_get_match_data(&pdev->dev); 225 data = of_device_get_match_data(&pdev->dev);
212 if (data == NULL) 226 if (data == NULL)
213 return -EINVAL; 227 return -EINVAL;
228 pc->soc = data;
214 229
215 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 230 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
216 pc->regs = devm_ioremap_resource(&pdev->dev, res); 231 pc->regs = devm_ioremap_resource(&pdev->dev, res);
@@ -251,14 +266,17 @@ static int mtk_pwm_remove(struct platform_device *pdev)
251 266
252static const struct mtk_pwm_platform_data mt2712_pwm_data = { 267static const struct mtk_pwm_platform_data mt2712_pwm_data = {
253 .num_pwms = 8, 268 .num_pwms = 8,
269 .pwm45_fixup = false,
254}; 270};
255 271
256static const struct mtk_pwm_platform_data mt7622_pwm_data = { 272static const struct mtk_pwm_platform_data mt7622_pwm_data = {
257 .num_pwms = 6, 273 .num_pwms = 6,
274 .pwm45_fixup = false,
258}; 275};
259 276
260static const struct mtk_pwm_platform_data mt7623_pwm_data = { 277static const struct mtk_pwm_platform_data mt7623_pwm_data = {
261 .num_pwms = 5, 278 .num_pwms = 5,
279 .pwm45_fixup = true,
262}; 280};
263 281
264static const struct of_device_id mtk_pwm_of_match[] = { 282static const struct of_device_id mtk_pwm_of_match[] = {