Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 358726
b: refs/heads/master
c: 8ab432c
h: refs/heads/master
v: v3
  • Loading branch information
Tony Prisk authored and Thierry Reding committed Jan 9, 2013
1 parent 86a21cf commit bc518d6
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 16 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9421bade0765d8ffb86b8a99213b611278a3542a
refs/heads/master: 8ab432caa46413c9f3ca81d82ea9fa5bae07c3c1
64 changes: 49 additions & 15 deletions trunk/drivers/pwm/pwm-vt8500.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,25 @@
*/
#define VT8500_NR_PWMS 2

#define REG_CTRL(pwm) (((pwm) << 4) + 0x00)
#define REG_SCALAR(pwm) (((pwm) << 4) + 0x04)
#define REG_PERIOD(pwm) (((pwm) << 4) + 0x08)
#define REG_DUTY(pwm) (((pwm) << 4) + 0x0C)
#define REG_STATUS 0x40

#define CTRL_ENABLE BIT(0)
#define CTRL_INVERT BIT(1)
#define CTRL_AUTOLOAD BIT(2)
#define CTRL_STOP_IMM BIT(3)
#define CTRL_LOAD_PRESCALE BIT(4)
#define CTRL_LOAD_PERIOD BIT(5)

#define STATUS_CTRL_UPDATE BIT(0)
#define STATUS_SCALAR_UPDATE BIT(1)
#define STATUS_PERIOD_UPDATE BIT(2)
#define STATUS_DUTY_UPDATE BIT(3)
#define STATUS_ALL_UPDATE 0x0F

struct vt8500_chip {
struct pwm_chip chip;
void __iomem *base;
Expand All @@ -45,15 +64,17 @@ struct vt8500_chip {
#define to_vt8500_chip(chip) container_of(chip, struct vt8500_chip, chip)

#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
static inline void pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask)
{
int loops = msecs_to_loops(10);
while ((readb(reg) & bitmask) && --loops)
u32 mask = bitmask << (nr << 8);

while ((readl(vt8500->base + REG_STATUS) & mask) && --loops)
cpu_relax();

if (unlikely(!loops))
pr_warn("Waiting for status bits 0x%x to clear timed out\n",
bitmask);
dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n",
mask);
}

static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
Expand All @@ -63,6 +84,7 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned long long c;
unsigned long period_cycles, prescale, pv, dc;
int err;
u32 val;

err = clk_enable(vt8500->clk);
if (err < 0) {
Expand Down Expand Up @@ -91,41 +113,53 @@ static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
do_div(c, period_ns);
dc = c;

pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 1));
writel(prescale, vt8500->base + 0x4 + (pwm->hwpwm << 4));
writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);

writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE);

pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2));
writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4));
writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE);

pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
val |= CTRL_AUTOLOAD;
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);

clk_disable(vt8500->clk);
return 0;
}

static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
int err;
struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
int err;
u32 val;

err = clk_enable(vt8500->clk);
if (err < 0) {
dev_err(chip->dev, "failed to enable clock\n");
return err;
}

pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
writel(5, vt8500->base + (pwm->hwpwm << 4));
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
val |= CTRL_ENABLE;
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);

return 0;
}

static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
u32 val;

pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
writel(0, vt8500->base + (pwm->hwpwm << 4));
val = readl(vt8500->base + REG_CTRL(pwm->hwpwm));
val &= ~CTRL_ENABLE;
writel(val, vt8500->base + REG_CTRL(pwm->hwpwm));
pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE);

clk_disable(vt8500->clk);
}
Expand Down

0 comments on commit bc518d6

Please sign in to comment.