static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct vt8500_chip *vt8500 = to_vt8500_chip(chip); unsigned long long c; unsigned long period_cycles, prescale, pv, dc; int err; u32 val; err = clk_enable(vt8500->clk); if (err < 0) { dev_err(chip->dev, "failed to enable clock\n"); return err; } c = clk_get_rate(vt8500->clk); c = c * period_ns; do_div(c, 1000000000); period_cycles = c; if (period_cycles < 1) period_cycles = 1; prescale = (period_cycles - 1) / 4096; pv = period_cycles / (prescale + 1) - 1; if (pv > 4095) pv = 4095; if (prescale > 1023) { clk_disable(vt8500->clk); return -EINVAL; } c = (unsigned long long)pv * duty_ns; do_div(c, period_ns); dc = c; 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); writel(dc, vt8500->base + REG_DUTY(pwm->hwpwm)); pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_DUTY_UPDATE); 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_config(struct pwm_chip *chip, struct pwm_device *pwm, int duty_ns, int period_ns) { struct vt8500_chip *vt8500 = to_vt8500_chip(chip); unsigned long long c; unsigned long period_cycles, prescale, pv, dc; int err; err = clk_enable(vt8500->clk); if (err < 0) { dev_err(chip->dev, "failed to enable clock\n"); return err; } c = clk_get_rate(vt8500->clk); c = c * period_ns; do_div(c, 1000000000); period_cycles = c; if (period_cycles < 1) period_cycles = 1; prescale = (period_cycles - 1) / 4096; pv = period_cycles / (prescale + 1) - 1; if (pv > 4095) pv = 4095; if (prescale > 1023) { clk_disable(vt8500->clk); return -EINVAL; } c = (unsigned long long)pv * duty_ns; 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)); pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2)); writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4)); pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3)); writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4)); clk_disable(vt8500->clk); return 0; }
static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct vt8500_chip *vt8500 = to_vt8500_chip(chip); pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0)); writel(0, vt8500->base + (pwm->hwpwm << 4)); clk_disable(vt8500->clk); }
static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct vt8500_chip *vt8500 = to_vt8500_chip(chip); u32 val; 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); }
static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { int err; struct vt8500_chip *vt8500 = to_vt8500_chip(chip); 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)); return 0; }
static int vt8500_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm, enum pwm_polarity polarity) { struct vt8500_chip *vt8500 = to_vt8500_chip(chip); u32 val; val = readl(vt8500->base + REG_CTRL(pwm->hwpwm)); if (polarity == PWM_POLARITY_INVERSED) val |= CTRL_INVERT; else val &= ~CTRL_INVERT; writel(val, vt8500->base + REG_CTRL(pwm->hwpwm)); pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_CTRL_UPDATE); return 0; }
static int vt8500_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) { 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; } 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; }