summaryrefslogtreecommitdiff
path: root/drivers/pwm/pwm-lpss.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-08-18 01:17:32 -0400
committerDavid S. Miller <davem@davemloft.net>2016-08-18 01:17:32 -0400
commit60747ef4d173c2747bf7f0377fb22846cb422195 (patch)
treeea0faf33b952495c47909be1400c475a3f3821b0 /drivers/pwm/pwm-lpss.c
parent484334198f8ce9552e20930fff9408ebf6bcf94d (diff)
parent184ca823481c99dadd7d946e5afd4bb921eab30d (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Minor overlapping changes for both merge conflicts. Resolution work done by Stephen Rothwell was used as a reference. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/pwm/pwm-lpss.c')
-rw-r--r--drivers/pwm/pwm-lpss.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index 295b963dbddb..72c0bce5a75c 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -27,7 +27,6 @@
#define PWM_SW_UPDATE BIT(30)
#define PWM_BASE_UNIT_SHIFT 8
#define PWM_ON_TIME_DIV_MASK 0x000000ff
-#define PWM_DIVISION_CORRECTION 0x2
/* Size of each PWM register space if multiple */
#define PWM_SIZE 0x400
@@ -92,8 +91,8 @@ 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 on_time_div;
- unsigned long c, base_unit_range;
+ unsigned long long on_time_div;
+ unsigned long c = lpwm->info->clk_rate, base_unit_range;
unsigned long long base_unit, freq = NSEC_PER_SEC;
u32 ctrl;
@@ -101,21 +100,18 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
/*
* The equation is:
- * base_unit = ((freq / c) * base_unit_range) + correction
+ * base_unit = round(base_unit_range * freq / c)
*/
base_unit_range = BIT(lpwm->info->base_unit_bits);
- base_unit = freq * base_unit_range;
+ freq *= base_unit_range;
- c = lpwm->info->clk_rate;
- if (!c)
- return -EINVAL;
-
- do_div(base_unit, c);
- base_unit += PWM_DIVISION_CORRECTION;
+ base_unit = DIV_ROUND_CLOSEST_ULL(freq, c);
if (duty_ns <= 0)
duty_ns = 1;
- on_time_div = 255 - (255 * duty_ns / period_ns);
+ on_time_div = 255ULL * duty_ns;
+ do_div(on_time_div, period_ns);
+ on_time_div = 255ULL - on_time_div;
pm_runtime_get_sync(chip->dev);
@@ -169,6 +165,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info)
{
struct pwm_lpss_chip *lpwm;
+ unsigned long c;
int ret;
lpwm = devm_kzalloc(dev, sizeof(*lpwm), GFP_KERNEL);
@@ -180,6 +177,11 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
return ERR_CAST(lpwm->regs);
lpwm->info = info;
+
+ c = lpwm->info->clk_rate;
+ if (!c)
+ return ERR_PTR(-EINVAL);
+
lpwm->chip.dev = dev;
lpwm->chip.ops = &pwm_lpss_ops;
lpwm->chip.base = -1;