1 /* drivers/pwm/pwm-samsung.c 2 * 3 * Copyright (c) 2007 Ben Dooks 4 * Copyright (c) 2008 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk>, <ben-linux@fluff.org> 6 * 7 * S3C series PWM device core 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License. 12 */ 13 14 #define pr_fmt(fmt) "pwm-samsung: " fmt 15 16 #include <linux/export.h> 17 #include <linux/kernel.h> 18 #include <linux/platform_device.h> 19 #include <linux/slab.h> 20 #include <linux/err.h> 21 #include <linux/clk.h> 22 #include <linux/io.h> 23 #include <linux/pwm.h> 24 25 #include <mach/map.h> 26 27 #include <plat/regs-timer.h> 28 29 struct s3c_chip { 30 struct platform_device *pdev; 31 32 struct clk *clk_div; 33 struct clk *clk; 34 const char *label; 35 36 unsigned int period_ns; 37 unsigned int duty_ns; 38 39 unsigned char tcon_base; 40 unsigned char pwm_id; 41 struct pwm_chip chip; 42 }; 43 44 #define to_s3c_chip(chip) container_of(chip, struct s3c_chip, chip) 45 46 #define pwm_dbg(_pwm, msg...) dev_dbg(&(_pwm)->pdev->dev, msg) 47 48 static struct clk *clk_scaler[2]; 49 50 static inline int pwm_is_tdiv(struct s3c_chip *chip) 51 { 52 return clk_get_parent(chip->clk) == chip->clk_div; 53 } 54 55 #define pwm_tcon_start(pwm) (1 << (pwm->tcon_base + 0)) 56 #define pwm_tcon_invert(pwm) (1 << (pwm->tcon_base + 2)) 57 #define pwm_tcon_autoreload(pwm) (1 << (pwm->tcon_base + 3)) 58 #define pwm_tcon_manulupdate(pwm) (1 << (pwm->tcon_base + 1)) 59 60 static int s3c_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) 61 { 62 struct s3c_chip *s3c = to_s3c_chip(chip); 63 unsigned long flags; 64 unsigned long tcon; 65 66 local_irq_save(flags); 67 68 tcon = __raw_readl(S3C2410_TCON); 69 tcon |= pwm_tcon_start(s3c); 70 __raw_writel(tcon, S3C2410_TCON); 71 72 local_irq_restore(flags); 73 74 return 0; 75 } 76 77 static void s3c_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) 78 { 79 struct s3c_chip *s3c = to_s3c_chip(chip); 80 unsigned long flags; 81 unsigned long tcon; 82 83 local_irq_save(flags); 84 85 tcon = __raw_readl(S3C2410_TCON); 86 tcon &= ~pwm_tcon_start(s3c); 87 __raw_writel(tcon, S3C2410_TCON); 88 89 local_irq_restore(flags); 90 } 91 92 static unsigned long pwm_calc_tin(struct s3c_chip *s3c, unsigned long freq) 93 { 94 unsigned long tin_parent_rate; 95 unsigned int div; 96 97 tin_parent_rate = clk_get_rate(clk_get_parent(s3c->clk_div)); 98 pwm_dbg(s3c, "tin parent at %lu\n", tin_parent_rate); 99 100 for (div = 2; div <= 16; div *= 2) { 101 if ((tin_parent_rate / (div << 16)) < freq) 102 return tin_parent_rate / div; 103 } 104 105 return tin_parent_rate / 16; 106 } 107 108 #define NS_IN_HZ (1000000000UL) 109 110 static int s3c_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, 111 int duty_ns, int period_ns) 112 { 113 struct s3c_chip *s3c = to_s3c_chip(chip); 114 unsigned long tin_rate; 115 unsigned long tin_ns; 116 unsigned long period; 117 unsigned long flags; 118 unsigned long tcon; 119 unsigned long tcnt; 120 long tcmp; 121 122 /* We currently avoid using 64bit arithmetic by using the 123 * fact that anything faster than 1Hz is easily representable 124 * by 32bits. */ 125 126 if (period_ns > NS_IN_HZ || duty_ns > NS_IN_HZ) 127 return -ERANGE; 128 129 if (period_ns == s3c->period_ns && 130 duty_ns == s3c->duty_ns) 131 return 0; 132 133 /* The TCMP and TCNT can be read without a lock, they're not 134 * shared between the timers. */ 135 136 tcmp = __raw_readl(S3C2410_TCMPB(s3c->pwm_id)); 137 tcnt = __raw_readl(S3C2410_TCNTB(s3c->pwm_id)); 138 139 period = NS_IN_HZ / period_ns; 140 141 pwm_dbg(s3c, "duty_ns=%d, period_ns=%d (%lu)\n", 142 duty_ns, period_ns, period); 143 144 /* Check to see if we are changing the clock rate of the PWM */ 145 146 if (s3c->period_ns != period_ns) { 147 if (pwm_is_tdiv(s3c)) { 148 tin_rate = pwm_calc_tin(s3c, period); 149 clk_set_rate(s3c->clk_div, tin_rate); 150 } else 151 tin_rate = clk_get_rate(s3c->clk); 152 153 s3c->period_ns = period_ns; 154 155 pwm_dbg(s3c, "tin_rate=%lu\n", tin_rate); 156 157 tin_ns = NS_IN_HZ / tin_rate; 158 tcnt = period_ns / tin_ns; 159 } else 160 tin_ns = NS_IN_HZ / clk_get_rate(s3c->clk); 161 162 /* Note, counters count down */ 163 164 tcmp = duty_ns / tin_ns; 165 tcmp = tcnt - tcmp; 166 /* the pwm hw only checks the compare register after a decrement, 167 so the pin never toggles if tcmp = tcnt */ 168 if (tcmp == tcnt) 169 tcmp--; 170 171 pwm_dbg(s3c, "tin_ns=%lu, tcmp=%ld/%lu\n", tin_ns, tcmp, tcnt); 172 173 if (tcmp < 0) 174 tcmp = 0; 175 176 /* Update the PWM register block. */ 177 178 local_irq_save(flags); 179 180 __raw_writel(tcmp, S3C2410_TCMPB(s3c->pwm_id)); 181 __raw_writel(tcnt, S3C2410_TCNTB(s3c->pwm_id)); 182 183 tcon = __raw_readl(S3C2410_TCON); 184 tcon |= pwm_tcon_manulupdate(s3c); 185 tcon |= pwm_tcon_autoreload(s3c); 186 __raw_writel(tcon, S3C2410_TCON); 187 188 tcon &= ~pwm_tcon_manulupdate(s3c); 189 __raw_writel(tcon, S3C2410_TCON); 190 191 local_irq_restore(flags); 192 193 return 0; 194 } 195 196 static struct pwm_ops s3c_pwm_ops = { 197 .enable = s3c_pwm_enable, 198 .disable = s3c_pwm_disable, 199 .config = s3c_pwm_config, 200 .owner = THIS_MODULE, 201 }; 202 203 static int s3c_pwm_probe(struct platform_device *pdev) 204 { 205 struct device *dev = &pdev->dev; 206 struct s3c_chip *s3c; 207 unsigned long flags; 208 unsigned long tcon; 209 unsigned int id = pdev->id; 210 int ret; 211 212 if (id == 4) { 213 dev_err(dev, "TIMER4 is currently not supported\n"); 214 return -ENXIO; 215 } 216 217 s3c = devm_kzalloc(&pdev->dev, sizeof(*s3c), GFP_KERNEL); 218 if (s3c == NULL) { 219 dev_err(dev, "failed to allocate pwm_device\n"); 220 return -ENOMEM; 221 } 222 223 /* calculate base of control bits in TCON */ 224 s3c->tcon_base = id == 0 ? 0 : (id * 4) + 4; 225 s3c->pwm_id = id; 226 s3c->chip.dev = &pdev->dev; 227 s3c->chip.ops = &s3c_pwm_ops; 228 s3c->chip.base = -1; 229 s3c->chip.npwm = 1; 230 231 s3c->clk = devm_clk_get(dev, "pwm-tin"); 232 if (IS_ERR(s3c->clk)) { 233 dev_err(dev, "failed to get pwm tin clk\n"); 234 return PTR_ERR(s3c->clk); 235 } 236 237 s3c->clk_div = devm_clk_get(dev, "pwm-tdiv"); 238 if (IS_ERR(s3c->clk_div)) { 239 dev_err(dev, "failed to get pwm tdiv clk\n"); 240 return PTR_ERR(s3c->clk_div); 241 } 242 243 clk_enable(s3c->clk); 244 clk_enable(s3c->clk_div); 245 246 local_irq_save(flags); 247 248 tcon = __raw_readl(S3C2410_TCON); 249 tcon |= pwm_tcon_invert(s3c); 250 __raw_writel(tcon, S3C2410_TCON); 251 252 local_irq_restore(flags); 253 254 ret = pwmchip_add(&s3c->chip); 255 if (ret < 0) { 256 dev_err(dev, "failed to register pwm\n"); 257 goto err_clk_tdiv; 258 } 259 260 pwm_dbg(s3c, "config bits %02x\n", 261 (__raw_readl(S3C2410_TCON) >> s3c->tcon_base) & 0x0f); 262 263 dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n", 264 clk_get_rate(s3c->clk), 265 clk_get_rate(s3c->clk_div), 266 pwm_is_tdiv(s3c) ? "div" : "ext", s3c->tcon_base); 267 268 platform_set_drvdata(pdev, s3c); 269 return 0; 270 271 err_clk_tdiv: 272 clk_disable(s3c->clk_div); 273 clk_disable(s3c->clk); 274 return ret; 275 } 276 277 static int s3c_pwm_remove(struct platform_device *pdev) 278 { 279 struct s3c_chip *s3c = platform_get_drvdata(pdev); 280 int err; 281 282 err = pwmchip_remove(&s3c->chip); 283 if (err < 0) 284 return err; 285 286 clk_disable(s3c->clk_div); 287 clk_disable(s3c->clk); 288 289 return 0; 290 } 291 292 #ifdef CONFIG_PM_SLEEP 293 static int s3c_pwm_suspend(struct device *dev) 294 { 295 struct s3c_chip *s3c = dev_get_drvdata(dev); 296 297 /* No one preserve these values during suspend so reset them 298 * Otherwise driver leaves PWM unconfigured if same values 299 * passed to pwm_config 300 */ 301 s3c->period_ns = 0; 302 s3c->duty_ns = 0; 303 304 return 0; 305 } 306 307 static int s3c_pwm_resume(struct device *dev) 308 { 309 struct s3c_chip *s3c = dev_get_drvdata(dev); 310 unsigned long tcon; 311 312 /* Restore invertion */ 313 tcon = __raw_readl(S3C2410_TCON); 314 tcon |= pwm_tcon_invert(s3c); 315 __raw_writel(tcon, S3C2410_TCON); 316 317 return 0; 318 } 319 #endif 320 321 static SIMPLE_DEV_PM_OPS(s3c_pwm_pm_ops, s3c_pwm_suspend, 322 s3c_pwm_resume); 323 324 static struct platform_driver s3c_pwm_driver = { 325 .driver = { 326 .name = "s3c24xx-pwm", 327 .owner = THIS_MODULE, 328 .pm = &s3c_pwm_pm_ops, 329 }, 330 .probe = s3c_pwm_probe, 331 .remove = s3c_pwm_remove, 332 }; 333 334 static int __init pwm_init(void) 335 { 336 int ret; 337 338 clk_scaler[0] = clk_get(NULL, "pwm-scaler0"); 339 clk_scaler[1] = clk_get(NULL, "pwm-scaler1"); 340 341 if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) { 342 pr_err("failed to get scaler clocks\n"); 343 return -EINVAL; 344 } 345 346 ret = platform_driver_register(&s3c_pwm_driver); 347 if (ret) 348 pr_err("failed to add pwm driver\n"); 349 350 return ret; 351 } 352 353 arch_initcall(pwm_init); 354