]> Git Repo - linux.git/blobdiff - drivers/pwm/pwm-berlin.c
Merge tag 'pm-4.19-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
[linux.git] / drivers / pwm / pwm-berlin.c
index 771859aca4be2b104e53f57f1271e8a2c7a9677d..7c8d6a168ceb254c69420ab293f08e3b43fcdd18 100644 (file)
 #define BERLIN_PWM_EN                  0x0
 #define  BERLIN_PWM_ENABLE             BIT(0)
 #define BERLIN_PWM_CONTROL             0x4
-#define  BERLIN_PWM_PRESCALE_MASK      0x7
-#define  BERLIN_PWM_PRESCALE_MAX       4096
+/*
+ * The prescaler claims to support 8 different moduli, configured using the
+ * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64,
+ * 256, 1024, and 4096.)  However, the moduli from 4 to 1024 appear to be
+ * implemented by internally shifting TCNT left without adding additional
+ * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff;
+ * for 8, 0x1fff; and so on. This means that those moduli are entirely
+ * useless, as we could just do the shift ourselves. The 4096 modulus is
+ * implemented with a real prescaler, so we do use that, but we treat it
+ * as a flag instead of pretending the modulus is actually configurable.
+ */
+#define  BERLIN_PWM_PRESCALE_4096      0x7
 #define  BERLIN_PWM_INVERT_POLARITY    BIT(3)
 #define BERLIN_PWM_DUTY                        0x8
 #define BERLIN_PWM_TCNT                        0xc
@@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
        return container_of(chip, struct berlin_pwm_chip, chip);
 }
 
-static const u32 prescaler_table[] = {
-       1, 4, 8, 16, 64, 256, 1024, 4096
-};
-
 static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
                                   unsigned int channel, unsigned long offset)
 {
@@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
                             int duty_ns, int period_ns)
 {
        struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
-       unsigned int prescale;
+       bool prescale_4096 = false;
        u32 value, duty, period;
-       u64 cycles, tmp;
+       u64 cycles;
 
        cycles = clk_get_rate(pwm->clk);
        cycles *= period_ns;
        do_div(cycles, NSEC_PER_SEC);
 
-       for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
-               tmp = cycles;
-               do_div(tmp, prescaler_table[prescale]);
+       if (cycles > BERLIN_PWM_MAX_TCNT) {
+               prescale_4096 = true;
+               cycles >>= 12; // Prescaled by 4096
 
-               if (tmp <= BERLIN_PWM_MAX_TCNT)
-                       break;
+               if (cycles > BERLIN_PWM_MAX_TCNT)
+                       return -ERANGE;
        }
 
-       if (tmp > BERLIN_PWM_MAX_TCNT)
-               return -ERANGE;
-
-       period = tmp;
-       cycles = tmp * duty_ns;
+       period = cycles;
+       cycles *= duty_ns;
        do_div(cycles, period_ns);
        duty = cycles;
 
        value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
-       value &= ~BERLIN_PWM_PRESCALE_MASK;
-       value |= prescale;
+       if (prescale_4096)
+               value |= BERLIN_PWM_PRESCALE_4096;
+       else
+               value &= ~BERLIN_PWM_PRESCALE_4096;
        berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
 
        berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
This page took 0.036456 seconds and 4 git commands to generate.