Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c500ce38 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-3.6-rc6' of git://gitorious.org/linux-pwm/linux-pwm

Pull pwm fixes from Thierry Reding:
 "While this comes a bit later than I had wished, both patches are
  rather minor and touch only new drivers so I think these are still
  safe for merging."

* tag 'for-3.6-rc6' of git://gitorious.org/linux-pwm/linux-pwm:
  pwm: pwm-tiehrpwm: Fix conflicting channel period setting
  pwm: pwm-tiecap: Disable APWM mode after configure
parents 76e77daf 01b2d453
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -100,6 +100,13 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
		writel(period_cycles, pc->mmio_base + CAP3);
	}

	if (!test_bit(PWMF_ENABLED, &pwm->flags)) {
		reg_val = readw(pc->mmio_base + ECCTL2);
		/* Disable APWM mode to put APWM output Low */
		reg_val &= ~ECCTL2_APWM_MODE;
		writew(reg_val, pc->mmio_base + ECCTL2);
	}

	pm_runtime_put_sync(pc->chip.dev);
	return 0;
}
+29 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ struct ehrpwm_pwm_chip {
	struct pwm_chip	chip;
	unsigned int	clk_rate;
	void __iomem	*mmio_base;
	unsigned long period_cycles[NUM_PWM_CHANNEL];
};

static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
@@ -210,6 +211,7 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
	unsigned long long c;
	unsigned long period_cycles, duty_cycles;
	unsigned short ps_divval, tb_divval;
	int i;

	if (period_ns < 0 || duty_ns < 0 || period_ns > NSEC_PER_SEC)
		return -ERANGE;
@@ -229,6 +231,28 @@ static int ehrpwm_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
		duty_cycles = (unsigned long)c;
	}

	/*
	 * Period values should be same for multiple PWM channels as IP uses
	 * same period register for multiple channels.
	 */
	for (i = 0; i < NUM_PWM_CHANNEL; i++) {
		if (pc->period_cycles[i] &&
				(pc->period_cycles[i] != period_cycles)) {
			/*
			 * Allow channel to reconfigure period if no other
			 * channels being configured.
			 */
			if (i == pwm->hwpwm)
				continue;

			dev_err(chip->dev, "Period value conflicts with channel %d\n",
					i);
			return -EINVAL;
		}
	}

	pc->period_cycles[pwm->hwpwm] = period_cycles;

	/* Configure clock prescaler to support Low frequency PWM wave */
	if (set_prescale_div(period_cycles/PERIOD_MAX, &ps_divval,
				&tb_divval)) {
@@ -320,10 +344,15 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)

static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);

	if (test_bit(PWMF_ENABLED, &pwm->flags)) {
		dev_warn(chip->dev, "Removing PWM device without disabling\n");
		pm_runtime_put_sync(chip->dev);
	}

	/* set period value to zero on free */
	pc->period_cycles[pwm->hwpwm] = 0;
}

static const struct pwm_ops ehrpwm_pwm_ops = {