blob: 79afa4679b18fb7ab5d2da585cf7a80f18a53701 [file] [log] [blame]
developer5d148cb2023-06-02 13:08:11 +08001From 58d5a373d2d42b5292c1c2242133bcf0b082c6e0 Mon Sep 17 00:00:00 2001
2From: Sam Shih <sam.shih@mediatek.com>
3Date: Fri, 2 Jun 2023 13:06:07 +0800
4Subject: [PATCH]
5 [slow-speed-io][999-2133-pwm-mediatek-add-longer-period-support.patch]
6
7---
8 drivers/pwm/pwm-mediatek.c | 34 ++++++++++++++++++++++++++++++----
9 1 file changed, 30 insertions(+), 4 deletions(-)
10
developer81ac79a2022-10-31 13:34:43 +080011diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
developer5d148cb2023-06-02 13:08:11 +080012index 9701092e7..79d15a9c0 100644
developer81ac79a2022-10-31 13:34:43 +080013--- a/drivers/pwm/pwm-mediatek.c
14+++ b/drivers/pwm/pwm-mediatek.c
15@@ -152,8 +152,11 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
16 int duty_ns, int period_ns)
17 {
18 struct pwm_mediatek_chip *pc = to_pwm_mediatek_chip(chip);
19- u32 clkdiv = 0, cnt_period, cnt_duty, reg_width = PWMDWIDTH,
20- reg_thres = PWMTHRES;
21+ /* The source clock is divided by 2^clkdiv or iff the clksel bit
22+ * is set by (2^clkdiv*1625)
23+ */
24+ u32 clkdiv = 0, clksel = 0, cnt_period, cnt_duty,
25+ reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
26 u64 resolution;
27 int ret;
28
29@@ -164,12 +167,30 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
30
31 /* Using resolution in picosecond gets accuracy higher */
32 resolution = (u64)NSEC_PER_SEC * 1000;
33+ /* Calculate resolution based on current clock frequency */
34 do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm]));
35-
36+ /* Using resolution to calculate cnt_period which represents
37+ * the effective range of the PWM period counter
38+ */
39 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
40 while (cnt_period > 8191) {
41+ /* Using clkdiv to reduce clock frequency and calculate
42+ * new resolution based on new clock speed
43+ */
44 resolution *= 2;
45 clkdiv++;
46+ if (clkdiv > PWM_CLK_DIV_MAX && !clksel) {
47+ /* Using clksel to divide the pwm source clock by
48+ * an additional 1625, and recalculate new clkdiv
49+ * and resolution
50+ */
51+ clksel = 1;
52+ clkdiv = 0;
53+ resolution = (u64)NSEC_PER_SEC * 1000 * 1625;
54+ do_div(resolution,
55+ clk_get_rate(pc->clk_pwms[pwm->hwpwm]));
56+ }
57+ /* Calculate cnt_period based on resolution */
58 cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000,
59 resolution);
60 }
61@@ -189,8 +210,13 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
62 reg_thres = PWM45THRES_FIXUP;
63 }
64
65+ /* Calculate cnt_duty based on resolution */
66 cnt_duty = DIV_ROUND_CLOSEST_ULL((u64)duty_ns * 1000, resolution);
67- pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv);
68+ if (clksel)
69+ pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | BIT(3) |
70+ clkdiv);
71+ else
72+ pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv);
73 pwm_mediatek_writel(pc, pwm->hwpwm, reg_width, cnt_period);
74 pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty);
75
developer5d148cb2023-06-02 13:08:11 +080076--
772.34.1
78