[linux-yocto] [PATCH 20/29] pwm: lpss: Fix base_unit calculation

rebecca.swee.fun.chang at intel.com rebecca.swee.fun.chang at intel.com
Mon Apr 7 08:18:11 PDT 2014


From: "Chew, Chiau Ee" <chiau.ee.chew at intel.com>

This to improve the accuracy of base_unit calculation
so that the resulting PWM frquency will be more
optimal.

Signed-off-by: Chew, Kean Ho <kean.ho.chew at intel.com>
Signed-off-by: Chew, Chiau Ee <chiau.ee.chew at intel.com>
Signed-off-by: Maurice Petallo <mauricex.r.petallo at intel.com>
---
 drivers/pwm/pwm-lpss.c |   25 ++++++++++---------------
 drivers/pwm/pwm-lpss.h |   14 ++++++++------
 2 files changed, 18 insertions(+), 21 deletions(-)

diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index eeed096..7fae747 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -35,32 +35,27 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
 	int duty_ns, int period_ns)
 {
 	struct pwm_lpss_chip *lpwm = to_lpwm(chip);
-	u8 base_unit_hi, base_unit_lo, on_time_div;
+	u8 on_time_div;
 	unsigned long c = clk_get_rate(lpwm->clk);
-	unsigned long hz, cycle_cnt;
+	unsigned long long base_unit, hz = 1000000000UL;
 	u32 ctrl;
 
-	hz = 1000000000UL / period_ns;
+	do_div(hz, period_ns);
 
-	/*
-	 * There is no duty cycle resolution if base_unit value is higher
-	 * than 128.
-	 */
-	base_unit_hi = (hz * 256) / c;
-	if (base_unit_hi > 128)
+	/* The equation is: base_unit = ((hz / c) * 65536) + correction */
+	base_unit = hz * 65536;
+	do_div(base_unit, c);
+	base_unit += PWM_DIVISION_CORRECTION;
+	if (base_unit > PWM_LIMIT)
 		return -EINVAL;
 
-	base_unit_lo = (hz * 65536) / c;
-	cycle_cnt = base_unit_hi ? 256 / base_unit_hi : 256;
-
 	if (duty_ns <= 0)
 		duty_ns = 1;
-
-	on_time_div = cycle_cnt / (period_ns / duty_ns);
+	on_time_div = 255 - (255 * duty_ns / period_ns);
 
 	ctrl = readl(lpwm->regs + PWM);
 	ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
-	ctrl |= (base_unit_hi | base_unit_lo) << PWM_BASE_UNIT_SHIFT;
+	ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
 	ctrl |= on_time_div;
 	/* request PWM to update on next cycle */
 	ctrl |= PWM_SW_UPDATE;
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index d1705e5..a9f2307 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -1,9 +1,11 @@
-#define PWM			0x00000000
-#define PWM_ENABLE		BIT(31)
-#define PWM_SW_UPDATE		BIT(30)
-#define PWM_BASE_UNIT_SHIFT	8
-#define PWM_BASE_UNIT_MASK	0x00ffff00
-#define PWM_ON_TIME_DIV_MASK	0x000000ff
+#define PWM				0x00000000
+#define PWM_ENABLE			BIT(31)
+#define PWM_SW_UPDATE			BIT(30)
+#define PWM_BASE_UNIT_SHIFT		8
+#define PWM_BASE_UNIT_MASK		0x00ffff00
+#define PWM_ON_TIME_DIV_MASK		0x000000ff
+#define PWM_DIVISION_CORRECTION		0x2
+#define PWM_LIMIT			(0x8000 + PWM_DIVISION_CORRECTION)
 
 struct pwm_lpss_chip {
 	struct pwm_chip chip;
-- 
1.7.10.4



More information about the linux-yocto mailing list