static void s3c_pwm_init(struct s3c_chip *s3c, struct s3c_pwm_device *s3c_pwm) { void __iomem *reg_base = s3c->reg_base; unsigned long tcon; unsigned int id = s3c_pwm->pwm_id; if (pwm_is_s3c24xx(s3c)) { tcon = __raw_readl(reg_base + REG_TCON); tcon |= pwm_tcon_invert(s3c_pwm); __raw_writel(tcon, reg_base + REG_TCON); } else { __raw_writel(0, reg_base + REG_TCMPB(id)); __raw_writel(0, reg_base + REG_TCNTB(id)); tcon = __raw_readl(reg_base + REG_TCON); tcon |= pwm_tcon_invert(s3c_pwm); tcon |= pwm_tcon_manulupdate(s3c_pwm); tcon &= ~pwm_tcon_autoreload(s3c_pwm); tcon &= ~pwm_tcon_start(s3c_pwm); __raw_writel(tcon, reg_base + REG_TCON); tcon &= ~pwm_tcon_manulupdate(s3c_pwm); __raw_writel(tcon, reg_base + REG_TCON); } }
static int s3c_pwm_resume(struct platform_device *pdev) { struct s3c_chip *s3c = platform_get_drvdata(pdev); unsigned long tcon; /* Restore invertion */ tcon = __raw_readl(S3C2410_TCON); tcon |= pwm_tcon_invert(s3c); __raw_writel(tcon, S3C2410_TCON); return 0; }
static int s3c_pwm_suspend(struct device *dev) { struct s3c_chip *s3c = dev_get_drvdata(dev); struct s3c_pwm_device *s3c_pwm; void __iomem *reg_base = s3c->reg_base; unsigned long tcon; unsigned char i; if (!pwm_is_s3c24xx(s3c)) { for (i = 0; i < NPWM; i++) { if (s3c->s3c_pwm[i] == NULL) continue; s3c_pwm = s3c->s3c_pwm[i]; if (s3c_pwm->running == 0) { tcon = __raw_readl(reg_base + REG_TCON); if (s3c_pwm->duty_cycle == DUTY_CYCLE_ZERO) { tcon |= pwm_tcon_manulupdate(s3c_pwm); } else if (s3c_pwm->duty_cycle == DUTY_CYCLE_FULL) { tcon &= pwm_tcon_invert(s3c_pwm); tcon |= pwm_tcon_manulupdate(s3c_pwm); } tcon &= ~pwm_tcon_start(s3c_pwm); __raw_writel(tcon, reg_base + REG_TCON); } /* No one preserve these values during suspend so reset them * Otherwise driver leaves PWM unconfigured if same values * passed to pwm_config */ s3c_pwm->duty_ns = -1; s3c_pwm->period_ns = -1; } } /* Save pwm registers*/ s3c->reg_tcfg0 = __raw_readl(s3c->reg_base + REG_TCFG0); clk_disable(s3c->clk); return 0; }
static int s3c_pwm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct s3c_chip *s3c; unsigned long flags; unsigned long tcon; unsigned int id = pdev->id; int ret; if (id == 4) { dev_err(dev, "TIMER4 is currently not supported\n"); return -ENXIO; } s3c = devm_kzalloc(&pdev->dev, sizeof(*s3c), GFP_KERNEL); if (s3c == NULL) { dev_err(dev, "failed to allocate pwm_device\n"); return -ENOMEM; } /* calculate base of control bits in TCON */ s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4; s3c->chip.dev = &pdev->dev; s3c->chip.ops = &s3c_pwm_ops; s3c->chip.base = -1; s3c->chip.npwm = 1; s3c->clk = devm_clk_get(dev, "pwm-tin"); if (IS_ERR(s3c->clk)) { dev_err(dev, "failed to get pwm tin clk\n"); return PTR_ERR(s3c->clk); } s3c->clk_div = devm_clk_get(dev, "pwm-tdiv"); if (IS_ERR(s3c->clk_div)) { dev_err(dev, "failed to get pwm tdiv clk\n"); return PTR_ERR(s3c->clk_div); } clk_enable(s3c->clk); clk_enable(s3c->clk_div); local_irq_save(flags); tcon = __raw_readl(S3C2410_TCON); tcon |= pwm_tcon_invert(s3c); __raw_writel(tcon, S3C2410_TCON); local_irq_restore(flags); ret = pwmchip_add(&s3c->chip); if (ret < 0) { dev_err(dev, "failed to register pwm\n"); goto err_clk_tdiv; } pwm_dbg(s3c, "config bits %02x\n", (__raw_readl(S3C2410_TCON) >> s3c->tcon_base) & 0x0f); dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", clk_get_rate(s3c->clk), clk_get_rate(s3c->clk_div), pwm_is_tdiv(s3c) ? "div" : "ext", s3c->tcon_base); platform_set_drvdata(pdev, s3c); return 0; err_clk_tdiv: clk_disable(s3c->clk_div); clk_disable(s3c->clk); return ret; }