root/drivers/pwm/pwm-fsl-ftm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_fsl_chip
  2. ftm_clear_write_protection
  3. ftm_set_write_protection
  4. fsl_pwm_periodcfg_are_equal
  5. fsl_pwm_request
  6. fsl_pwm_free
  7. fsl_pwm_ticks_to_ns
  8. fsl_pwm_calculate_period_clk
  9. fsl_pwm_calculate_period
  10. fsl_pwm_calculate_duty
  11. fsl_pwm_is_any_pwm_enabled
  12. fsl_pwm_is_other_pwm_enabled
  13. fsl_pwm_apply_config
  14. fsl_pwm_apply
  15. fsl_pwm_init
  16. fsl_pwm_volatile_reg
  17. fsl_pwm_probe
  18. fsl_pwm_remove
  19. fsl_pwm_suspend
  20. fsl_pwm_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  Freescale FlexTimer Module (FTM) PWM Driver
   4  *
   5  *  Copyright 2012-2013 Freescale Semiconductor, Inc.
   6  */
   7 
   8 #include <linux/clk.h>
   9 #include <linux/err.h>
  10 #include <linux/io.h>
  11 #include <linux/kernel.h>
  12 #include <linux/module.h>
  13 #include <linux/mutex.h>
  14 #include <linux/of_address.h>
  15 #include <linux/of_device.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/pm.h>
  18 #include <linux/pwm.h>
  19 #include <linux/regmap.h>
  20 #include <linux/slab.h>
  21 #include <linux/fsl/ftm.h>
  22 
  23 #define FTM_SC_CLK(c)   (((c) + 1) << FTM_SC_CLK_MASK_SHIFT)
  24 
  25 enum fsl_pwm_clk {
  26         FSL_PWM_CLK_SYS,
  27         FSL_PWM_CLK_FIX,
  28         FSL_PWM_CLK_EXT,
  29         FSL_PWM_CLK_CNTEN,
  30         FSL_PWM_CLK_MAX
  31 };
  32 
  33 struct fsl_ftm_soc {
  34         bool has_enable_bits;
  35 };
  36 
  37 struct fsl_pwm_periodcfg {
  38         enum fsl_pwm_clk clk_select;
  39         unsigned int clk_ps;
  40         unsigned int mod_period;
  41 };
  42 
  43 struct fsl_pwm_chip {
  44         struct pwm_chip chip;
  45         struct mutex lock;
  46         struct regmap *regmap;
  47 
  48         /* This value is valid iff a pwm is running */
  49         struct fsl_pwm_periodcfg period;
  50 
  51         struct clk *ipg_clk;
  52         struct clk *clk[FSL_PWM_CLK_MAX];
  53 
  54         const struct fsl_ftm_soc *soc;
  55 };
  56 
  57 static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip)
  58 {
  59         return container_of(chip, struct fsl_pwm_chip, chip);
  60 }
  61 
  62 static void ftm_clear_write_protection(struct fsl_pwm_chip *fpc)
  63 {
  64         u32 val;
  65 
  66         regmap_read(fpc->regmap, FTM_FMS, &val);
  67         if (val & FTM_FMS_WPEN)
  68                 regmap_update_bits(fpc->regmap, FTM_MODE, FTM_MODE_WPDIS,
  69                                    FTM_MODE_WPDIS);
  70 }
  71 
  72 static void ftm_set_write_protection(struct fsl_pwm_chip *fpc)
  73 {
  74         regmap_update_bits(fpc->regmap, FTM_FMS, FTM_FMS_WPEN, FTM_FMS_WPEN);
  75 }
  76 
  77 static bool fsl_pwm_periodcfg_are_equal(const struct fsl_pwm_periodcfg *a,
  78                                         const struct fsl_pwm_periodcfg *b)
  79 {
  80         if (a->clk_select != b->clk_select)
  81                 return false;
  82         if (a->clk_ps != b->clk_ps)
  83                 return false;
  84         if (a->mod_period != b->mod_period)
  85                 return false;
  86         return true;
  87 }
  88 
  89 static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
  90 {
  91         int ret;
  92         struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
  93 
  94         ret = clk_prepare_enable(fpc->ipg_clk);
  95         if (!ret && fpc->soc->has_enable_bits) {
  96                 mutex_lock(&fpc->lock);
  97                 regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16),
  98                                    BIT(pwm->hwpwm + 16));
  99                 mutex_unlock(&fpc->lock);
 100         }
 101 
 102         return ret;
 103 }
 104 
 105 static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
 106 {
 107         struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 108 
 109         if (fpc->soc->has_enable_bits) {
 110                 mutex_lock(&fpc->lock);
 111                 regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16),
 112                                    0);
 113                 mutex_unlock(&fpc->lock);
 114         }
 115 
 116         clk_disable_unprepare(fpc->ipg_clk);
 117 }
 118 
 119 static unsigned int fsl_pwm_ticks_to_ns(struct fsl_pwm_chip *fpc,
 120                                           unsigned int ticks)
 121 {
 122         unsigned long rate;
 123         unsigned long long exval;
 124 
 125         rate = clk_get_rate(fpc->clk[fpc->period.clk_select]);
 126         exval = ticks;
 127         exval *= 1000000000UL;
 128         do_div(exval, rate >> fpc->period.clk_ps);
 129         return exval;
 130 }
 131 
 132 static bool fsl_pwm_calculate_period_clk(struct fsl_pwm_chip *fpc,
 133                                          unsigned int period_ns,
 134                                          enum fsl_pwm_clk index,
 135                                          struct fsl_pwm_periodcfg *periodcfg
 136                                          )
 137 {
 138         unsigned long long c;
 139         unsigned int ps;
 140 
 141         c = clk_get_rate(fpc->clk[index]);
 142         c = c * period_ns;
 143         do_div(c, 1000000000UL);
 144 
 145         if (c == 0)
 146                 return false;
 147 
 148         for (ps = 0; ps < 8 ; ++ps, c >>= 1) {
 149                 if (c <= 0x10000) {
 150                         periodcfg->clk_select = index;
 151                         periodcfg->clk_ps = ps;
 152                         periodcfg->mod_period = c - 1;
 153                         return true;
 154                 }
 155         }
 156         return false;
 157 }
 158 
 159 static bool fsl_pwm_calculate_period(struct fsl_pwm_chip *fpc,
 160                                      unsigned int period_ns,
 161                                      struct fsl_pwm_periodcfg *periodcfg)
 162 {
 163         enum fsl_pwm_clk m0, m1;
 164         unsigned long fix_rate, ext_rate;
 165         bool ret;
 166 
 167         ret = fsl_pwm_calculate_period_clk(fpc, period_ns, FSL_PWM_CLK_SYS,
 168                                            periodcfg);
 169         if (ret)
 170                 return true;
 171 
 172         fix_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_FIX]);
 173         ext_rate = clk_get_rate(fpc->clk[FSL_PWM_CLK_EXT]);
 174 
 175         if (fix_rate > ext_rate) {
 176                 m0 = FSL_PWM_CLK_FIX;
 177                 m1 = FSL_PWM_CLK_EXT;
 178         } else {
 179                 m0 = FSL_PWM_CLK_EXT;
 180                 m1 = FSL_PWM_CLK_FIX;
 181         }
 182 
 183         ret = fsl_pwm_calculate_period_clk(fpc, period_ns, m0, periodcfg);
 184         if (ret)
 185                 return true;
 186 
 187         return fsl_pwm_calculate_period_clk(fpc, period_ns, m1, periodcfg);
 188 }
 189 
 190 static unsigned int fsl_pwm_calculate_duty(struct fsl_pwm_chip *fpc,
 191                                            unsigned int duty_ns)
 192 {
 193         unsigned long long duty;
 194 
 195         unsigned int period = fpc->period.mod_period + 1;
 196         unsigned int period_ns = fsl_pwm_ticks_to_ns(fpc, period);
 197 
 198         duty = (unsigned long long)duty_ns * period;
 199         do_div(duty, period_ns);
 200 
 201         return (unsigned int)duty;
 202 }
 203 
 204 static bool fsl_pwm_is_any_pwm_enabled(struct fsl_pwm_chip *fpc,
 205                                        struct pwm_device *pwm)
 206 {
 207         u32 val;
 208 
 209         regmap_read(fpc->regmap, FTM_OUTMASK, &val);
 210         if (~val & 0xFF)
 211                 return true;
 212         else
 213                 return false;
 214 }
 215 
 216 static bool fsl_pwm_is_other_pwm_enabled(struct fsl_pwm_chip *fpc,
 217                                          struct pwm_device *pwm)
 218 {
 219         u32 val;
 220 
 221         regmap_read(fpc->regmap, FTM_OUTMASK, &val);
 222         if (~(val | BIT(pwm->hwpwm)) & 0xFF)
 223                 return true;
 224         else
 225                 return false;
 226 }
 227 
 228 static int fsl_pwm_apply_config(struct fsl_pwm_chip *fpc,
 229                                 struct pwm_device *pwm,
 230                                 const struct pwm_state *newstate)
 231 {
 232         unsigned int duty;
 233         u32 reg_polarity;
 234 
 235         struct fsl_pwm_periodcfg periodcfg;
 236         bool do_write_period = false;
 237 
 238         if (!fsl_pwm_calculate_period(fpc, newstate->period, &periodcfg)) {
 239                 dev_err(fpc->chip.dev, "failed to calculate new period\n");
 240                 return -EINVAL;
 241         }
 242 
 243         if (!fsl_pwm_is_any_pwm_enabled(fpc, pwm))
 244                 do_write_period = true;
 245         /*
 246          * The Freescale FTM controller supports only a single period for
 247          * all PWM channels, therefore verify if the newly computed period
 248          * is different than the current period being used. In such case
 249          * we allow to change the period only if no other pwm is running.
 250          */
 251         else if (!fsl_pwm_periodcfg_are_equal(&fpc->period, &periodcfg)) {
 252                 if (fsl_pwm_is_other_pwm_enabled(fpc, pwm)) {
 253                         dev_err(fpc->chip.dev,
 254                                 "Cannot change period for PWM %u, disable other PWMs first\n",
 255                                 pwm->hwpwm);
 256                         return -EBUSY;
 257                 }
 258                 if (fpc->period.clk_select != periodcfg.clk_select) {
 259                         int ret;
 260                         enum fsl_pwm_clk oldclk = fpc->period.clk_select;
 261                         enum fsl_pwm_clk newclk = periodcfg.clk_select;
 262 
 263                         ret = clk_prepare_enable(fpc->clk[newclk]);
 264                         if (ret)
 265                                 return ret;
 266                         clk_disable_unprepare(fpc->clk[oldclk]);
 267                 }
 268                 do_write_period = true;
 269         }
 270 
 271         ftm_clear_write_protection(fpc);
 272 
 273         if (do_write_period) {
 274                 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_CLK_MASK,
 275                                    FTM_SC_CLK(periodcfg.clk_select));
 276                 regmap_update_bits(fpc->regmap, FTM_SC, FTM_SC_PS_MASK,
 277                                    periodcfg.clk_ps);
 278                 regmap_write(fpc->regmap, FTM_MOD, periodcfg.mod_period);
 279 
 280                 fpc->period = periodcfg;
 281         }
 282 
 283         duty = fsl_pwm_calculate_duty(fpc, newstate->duty_cycle);
 284 
 285         regmap_write(fpc->regmap, FTM_CSC(pwm->hwpwm),
 286                      FTM_CSC_MSB | FTM_CSC_ELSB);
 287         regmap_write(fpc->regmap, FTM_CV(pwm->hwpwm), duty);
 288 
 289         reg_polarity = 0;
 290         if (newstate->polarity == PWM_POLARITY_INVERSED)
 291                 reg_polarity = BIT(pwm->hwpwm);
 292 
 293         regmap_update_bits(fpc->regmap, FTM_POL, BIT(pwm->hwpwm), reg_polarity);
 294 
 295         ftm_set_write_protection(fpc);
 296 
 297         return 0;
 298 }
 299 
 300 static int fsl_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
 301                          const struct pwm_state *newstate)
 302 {
 303         struct fsl_pwm_chip *fpc = to_fsl_chip(chip);
 304         struct pwm_state *oldstate = &pwm->state;
 305         int ret = 0;
 306 
 307         /*
 308          * oldstate to newstate : action
 309          *
 310          * disabled to disabled : ignore
 311          * enabled to disabled : disable
 312          * enabled to enabled : update settings
 313          * disabled to enabled : update settings + enable
 314          */
 315 
 316         mutex_lock(&fpc->lock);
 317 
 318         if (!newstate->enabled) {
 319                 if (oldstate->enabled) {
 320                         regmap_update_bits(fpc->regmap, FTM_OUTMASK,
 321                                            BIT(pwm->hwpwm), BIT(pwm->hwpwm));
 322                         clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
 323                         clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
 324                 }
 325 
 326                 goto end_mutex;
 327         }
 328 
 329         ret = fsl_pwm_apply_config(fpc, pwm, newstate);
 330         if (ret)
 331                 goto end_mutex;
 332 
 333         /* check if need to enable */
 334         if (!oldstate->enabled) {
 335                 ret = clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
 336                 if (ret)
 337                         goto end_mutex;
 338 
 339                 ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
 340                 if (ret) {
 341                         clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
 342                         goto end_mutex;
 343                 }
 344 
 345                 regmap_update_bits(fpc->regmap, FTM_OUTMASK, BIT(pwm->hwpwm),
 346                                    0);
 347         }
 348 
 349 end_mutex:
 350         mutex_unlock(&fpc->lock);
 351         return ret;
 352 }
 353 
 354 static const struct pwm_ops fsl_pwm_ops = {
 355         .request = fsl_pwm_request,
 356         .free = fsl_pwm_free,
 357         .apply = fsl_pwm_apply,
 358         .owner = THIS_MODULE,
 359 };
 360 
 361 static int fsl_pwm_init(struct fsl_pwm_chip *fpc)
 362 {
 363         int ret;
 364 
 365         ret = clk_prepare_enable(fpc->ipg_clk);
 366         if (ret)
 367                 return ret;
 368 
 369         regmap_write(fpc->regmap, FTM_CNTIN, 0x00);
 370         regmap_write(fpc->regmap, FTM_OUTINIT, 0x00);
 371         regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF);
 372 
 373         clk_disable_unprepare(fpc->ipg_clk);
 374 
 375         return 0;
 376 }
 377 
 378 static bool fsl_pwm_volatile_reg(struct device *dev, unsigned int reg)
 379 {
 380         switch (reg) {
 381         case FTM_FMS:
 382         case FTM_MODE:
 383         case FTM_CNT:
 384                 return true;
 385         }
 386         return false;
 387 }
 388 
 389 static const struct regmap_config fsl_pwm_regmap_config = {
 390         .reg_bits = 32,
 391         .reg_stride = 4,
 392         .val_bits = 32,
 393 
 394         .max_register = FTM_PWMLOAD,
 395         .volatile_reg = fsl_pwm_volatile_reg,
 396         .cache_type = REGCACHE_FLAT,
 397 };
 398 
 399 static int fsl_pwm_probe(struct platform_device *pdev)
 400 {
 401         struct fsl_pwm_chip *fpc;
 402         struct resource *res;
 403         void __iomem *base;
 404         int ret;
 405 
 406         fpc = devm_kzalloc(&pdev->dev, sizeof(*fpc), GFP_KERNEL);
 407         if (!fpc)
 408                 return -ENOMEM;
 409 
 410         mutex_init(&fpc->lock);
 411 
 412         fpc->soc = of_device_get_match_data(&pdev->dev);
 413         fpc->chip.dev = &pdev->dev;
 414 
 415         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 416         base = devm_ioremap_resource(&pdev->dev, res);
 417         if (IS_ERR(base))
 418                 return PTR_ERR(base);
 419 
 420         fpc->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "ftm_sys", base,
 421                                                 &fsl_pwm_regmap_config);
 422         if (IS_ERR(fpc->regmap)) {
 423                 dev_err(&pdev->dev, "regmap init failed\n");
 424                 return PTR_ERR(fpc->regmap);
 425         }
 426 
 427         fpc->clk[FSL_PWM_CLK_SYS] = devm_clk_get(&pdev->dev, "ftm_sys");
 428         if (IS_ERR(fpc->clk[FSL_PWM_CLK_SYS])) {
 429                 dev_err(&pdev->dev, "failed to get \"ftm_sys\" clock\n");
 430                 return PTR_ERR(fpc->clk[FSL_PWM_CLK_SYS]);
 431         }
 432 
 433         fpc->clk[FSL_PWM_CLK_FIX] = devm_clk_get(fpc->chip.dev, "ftm_fix");
 434         if (IS_ERR(fpc->clk[FSL_PWM_CLK_FIX]))
 435                 return PTR_ERR(fpc->clk[FSL_PWM_CLK_FIX]);
 436 
 437         fpc->clk[FSL_PWM_CLK_EXT] = devm_clk_get(fpc->chip.dev, "ftm_ext");
 438         if (IS_ERR(fpc->clk[FSL_PWM_CLK_EXT]))
 439                 return PTR_ERR(fpc->clk[FSL_PWM_CLK_EXT]);
 440 
 441         fpc->clk[FSL_PWM_CLK_CNTEN] =
 442                                 devm_clk_get(fpc->chip.dev, "ftm_cnt_clk_en");
 443         if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]))
 444                 return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]);
 445 
 446         /*
 447          * ipg_clk is the interface clock for the IP. If not provided, use the
 448          * ftm_sys clock as the default.
 449          */
 450         fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg");
 451         if (IS_ERR(fpc->ipg_clk))
 452                 fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS];
 453 
 454 
 455         fpc->chip.ops = &fsl_pwm_ops;
 456         fpc->chip.of_xlate = of_pwm_xlate_with_flags;
 457         fpc->chip.of_pwm_n_cells = 3;
 458         fpc->chip.base = -1;
 459         fpc->chip.npwm = 8;
 460 
 461         ret = pwmchip_add(&fpc->chip);
 462         if (ret < 0) {
 463                 dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
 464                 return ret;
 465         }
 466 
 467         platform_set_drvdata(pdev, fpc);
 468 
 469         return fsl_pwm_init(fpc);
 470 }
 471 
 472 static int fsl_pwm_remove(struct platform_device *pdev)
 473 {
 474         struct fsl_pwm_chip *fpc = platform_get_drvdata(pdev);
 475 
 476         return pwmchip_remove(&fpc->chip);
 477 }
 478 
 479 #ifdef CONFIG_PM_SLEEP
 480 static int fsl_pwm_suspend(struct device *dev)
 481 {
 482         struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
 483         int i;
 484 
 485         regcache_cache_only(fpc->regmap, true);
 486         regcache_mark_dirty(fpc->regmap);
 487 
 488         for (i = 0; i < fpc->chip.npwm; i++) {
 489                 struct pwm_device *pwm = &fpc->chip.pwms[i];
 490 
 491                 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
 492                         continue;
 493 
 494                 clk_disable_unprepare(fpc->ipg_clk);
 495 
 496                 if (!pwm_is_enabled(pwm))
 497                         continue;
 498 
 499                 clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_CNTEN]);
 500                 clk_disable_unprepare(fpc->clk[fpc->period.clk_select]);
 501         }
 502 
 503         return 0;
 504 }
 505 
 506 static int fsl_pwm_resume(struct device *dev)
 507 {
 508         struct fsl_pwm_chip *fpc = dev_get_drvdata(dev);
 509         int i;
 510 
 511         for (i = 0; i < fpc->chip.npwm; i++) {
 512                 struct pwm_device *pwm = &fpc->chip.pwms[i];
 513 
 514                 if (!test_bit(PWMF_REQUESTED, &pwm->flags))
 515                         continue;
 516 
 517                 clk_prepare_enable(fpc->ipg_clk);
 518 
 519                 if (!pwm_is_enabled(pwm))
 520                         continue;
 521 
 522                 clk_prepare_enable(fpc->clk[fpc->period.clk_select]);
 523                 clk_prepare_enable(fpc->clk[FSL_PWM_CLK_CNTEN]);
 524         }
 525 
 526         /* restore all registers from cache */
 527         regcache_cache_only(fpc->regmap, false);
 528         regcache_sync(fpc->regmap);
 529 
 530         return 0;
 531 }
 532 #endif
 533 
 534 static const struct dev_pm_ops fsl_pwm_pm_ops = {
 535         SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume)
 536 };
 537 
 538 static const struct fsl_ftm_soc vf610_ftm_pwm = {
 539         .has_enable_bits = false,
 540 };
 541 
 542 static const struct fsl_ftm_soc imx8qm_ftm_pwm = {
 543         .has_enable_bits = true,
 544 };
 545 
 546 static const struct of_device_id fsl_pwm_dt_ids[] = {
 547         { .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm },
 548         { .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm },
 549         { /* sentinel */ }
 550 };
 551 MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids);
 552 
 553 static struct platform_driver fsl_pwm_driver = {
 554         .driver = {
 555                 .name = "fsl-ftm-pwm",
 556                 .of_match_table = fsl_pwm_dt_ids,
 557                 .pm = &fsl_pwm_pm_ops,
 558         },
 559         .probe = fsl_pwm_probe,
 560         .remove = fsl_pwm_remove,
 561 };
 562 module_platform_driver(fsl_pwm_driver);
 563 
 564 MODULE_DESCRIPTION("Freescale FlexTimer Module PWM Driver");
 565 MODULE_AUTHOR("Xiubo Li <Li.Xiubo@freescale.com>");
 566 MODULE_ALIAS("platform:fsl-ftm-pwm");
 567 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */