root/drivers/pwm/pwm-samsung.c

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

DEFINITIONS

This source file includes following definitions.
  1. to_samsung_pwm_chip
  2. to_tcon_channel
  3. pwm_samsung_set_divisor
  4. pwm_samsung_is_tdiv
  5. pwm_samsung_get_tin_rate
  6. pwm_samsung_calc_tin
  7. pwm_samsung_request
  8. pwm_samsung_free
  9. pwm_samsung_enable
  10. pwm_samsung_disable
  11. pwm_samsung_manual_update
  12. __pwm_samsung_config
  13. pwm_samsung_config
  14. pwm_samsung_set_invert
  15. pwm_samsung_set_polarity
  16. pwm_samsung_parse_dt
  17. pwm_samsung_parse_dt
  18. pwm_samsung_probe
  19. pwm_samsung_remove
  20. pwm_samsung_resume

   1 // SPDX-License-Identifier: GPL-2.0-only
   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  * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
   7  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
   8  *
   9  * PWM driver for Samsung SoCs
  10  */
  11 
  12 #include <linux/bitops.h>
  13 #include <linux/clk.h>
  14 #include <linux/export.h>
  15 #include <linux/err.h>
  16 #include <linux/io.h>
  17 #include <linux/kernel.h>
  18 #include <linux/module.h>
  19 #include <linux/of.h>
  20 #include <linux/platform_device.h>
  21 #include <linux/pwm.h>
  22 #include <linux/slab.h>
  23 #include <linux/spinlock.h>
  24 #include <linux/time.h>
  25 
  26 /* For struct samsung_timer_variant and samsung_pwm_lock. */
  27 #include <clocksource/samsung_pwm.h>
  28 
  29 #define REG_TCFG0                       0x00
  30 #define REG_TCFG1                       0x04
  31 #define REG_TCON                        0x08
  32 
  33 #define REG_TCNTB(chan)                 (0x0c + ((chan) * 0xc))
  34 #define REG_TCMPB(chan)                 (0x10 + ((chan) * 0xc))
  35 
  36 #define TCFG0_PRESCALER_MASK            0xff
  37 #define TCFG0_PRESCALER1_SHIFT          8
  38 
  39 #define TCFG1_MUX_MASK                  0xf
  40 #define TCFG1_SHIFT(chan)               (4 * (chan))
  41 
  42 /*
  43  * Each channel occupies 4 bits in TCON register, but there is a gap of 4
  44  * bits (one channel) after channel 0, so channels have different numbering
  45  * when accessing TCON register. See to_tcon_channel() function.
  46  *
  47  * In addition, the location of autoreload bit for channel 4 (TCON channel 5)
  48  * in its set of bits is 2 as opposed to 3 for other channels.
  49  */
  50 #define TCON_START(chan)                BIT(4 * (chan) + 0)
  51 #define TCON_MANUALUPDATE(chan)         BIT(4 * (chan) + 1)
  52 #define TCON_INVERT(chan)               BIT(4 * (chan) + 2)
  53 #define _TCON_AUTORELOAD(chan)          BIT(4 * (chan) + 3)
  54 #define _TCON_AUTORELOAD4(chan)         BIT(4 * (chan) + 2)
  55 #define TCON_AUTORELOAD(chan)           \
  56         ((chan < 5) ? _TCON_AUTORELOAD(chan) : _TCON_AUTORELOAD4(chan))
  57 
  58 /**
  59  * struct samsung_pwm_channel - private data of PWM channel
  60  * @period_ns:  current period in nanoseconds programmed to the hardware
  61  * @duty_ns:    current duty time in nanoseconds programmed to the hardware
  62  * @tin_ns:     time of one timer tick in nanoseconds with current timer rate
  63  */
  64 struct samsung_pwm_channel {
  65         u32 period_ns;
  66         u32 duty_ns;
  67         u32 tin_ns;
  68 };
  69 
  70 /**
  71  * struct samsung_pwm_chip - private data of PWM chip
  72  * @chip:               generic PWM chip
  73  * @variant:            local copy of hardware variant data
  74  * @inverter_mask:      inverter status for all channels - one bit per channel
  75  * @disabled_mask:      disabled status for all channels - one bit per channel
  76  * @base:               base address of mapped PWM registers
  77  * @base_clk:           base clock used to drive the timers
  78  * @tclk0:              external clock 0 (can be ERR_PTR if not present)
  79  * @tclk1:              external clock 1 (can be ERR_PTR if not present)
  80  */
  81 struct samsung_pwm_chip {
  82         struct pwm_chip chip;
  83         struct samsung_pwm_variant variant;
  84         u8 inverter_mask;
  85         u8 disabled_mask;
  86 
  87         void __iomem *base;
  88         struct clk *base_clk;
  89         struct clk *tclk0;
  90         struct clk *tclk1;
  91 };
  92 
  93 #ifndef CONFIG_CLKSRC_SAMSUNG_PWM
  94 /*
  95  * PWM block is shared between pwm-samsung and samsung_pwm_timer drivers
  96  * and some registers need access synchronization. If both drivers are
  97  * compiled in, the spinlock is defined in the clocksource driver,
  98  * otherwise following definition is used.
  99  *
 100  * Currently we do not need any more complex synchronization method
 101  * because all the supported SoCs contain only one instance of the PWM
 102  * IP. Should this change, both drivers will need to be modified to
 103  * properly synchronize accesses to particular instances.
 104  */
 105 static DEFINE_SPINLOCK(samsung_pwm_lock);
 106 #endif
 107 
 108 static inline
 109 struct samsung_pwm_chip *to_samsung_pwm_chip(struct pwm_chip *chip)
 110 {
 111         return container_of(chip, struct samsung_pwm_chip, chip);
 112 }
 113 
 114 static inline unsigned int to_tcon_channel(unsigned int channel)
 115 {
 116         /* TCON register has a gap of 4 bits (1 channel) after channel 0 */
 117         return (channel == 0) ? 0 : (channel + 1);
 118 }
 119 
 120 static void pwm_samsung_set_divisor(struct samsung_pwm_chip *pwm,
 121                                     unsigned int channel, u8 divisor)
 122 {
 123         u8 shift = TCFG1_SHIFT(channel);
 124         unsigned long flags;
 125         u32 reg;
 126         u8 bits;
 127 
 128         bits = (fls(divisor) - 1) - pwm->variant.div_base;
 129 
 130         spin_lock_irqsave(&samsung_pwm_lock, flags);
 131 
 132         reg = readl(pwm->base + REG_TCFG1);
 133         reg &= ~(TCFG1_MUX_MASK << shift);
 134         reg |= bits << shift;
 135         writel(reg, pwm->base + REG_TCFG1);
 136 
 137         spin_unlock_irqrestore(&samsung_pwm_lock, flags);
 138 }
 139 
 140 static int pwm_samsung_is_tdiv(struct samsung_pwm_chip *chip, unsigned int chan)
 141 {
 142         struct samsung_pwm_variant *variant = &chip->variant;
 143         u32 reg;
 144 
 145         reg = readl(chip->base + REG_TCFG1);
 146         reg >>= TCFG1_SHIFT(chan);
 147         reg &= TCFG1_MUX_MASK;
 148 
 149         return (BIT(reg) & variant->tclk_mask) == 0;
 150 }
 151 
 152 static unsigned long pwm_samsung_get_tin_rate(struct samsung_pwm_chip *chip,
 153                                               unsigned int chan)
 154 {
 155         unsigned long rate;
 156         u32 reg;
 157 
 158         rate = clk_get_rate(chip->base_clk);
 159 
 160         reg = readl(chip->base + REG_TCFG0);
 161         if (chan >= 2)
 162                 reg >>= TCFG0_PRESCALER1_SHIFT;
 163         reg &= TCFG0_PRESCALER_MASK;
 164 
 165         return rate / (reg + 1);
 166 }
 167 
 168 static unsigned long pwm_samsung_calc_tin(struct samsung_pwm_chip *chip,
 169                                           unsigned int chan, unsigned long freq)
 170 {
 171         struct samsung_pwm_variant *variant = &chip->variant;
 172         unsigned long rate;
 173         struct clk *clk;
 174         u8 div;
 175 
 176         if (!pwm_samsung_is_tdiv(chip, chan)) {
 177                 clk = (chan < 2) ? chip->tclk0 : chip->tclk1;
 178                 if (!IS_ERR(clk)) {
 179                         rate = clk_get_rate(clk);
 180                         if (rate)
 181                                 return rate;
 182                 }
 183 
 184                 dev_warn(chip->chip.dev,
 185                         "tclk of PWM %d is inoperational, using tdiv\n", chan);
 186         }
 187 
 188         rate = pwm_samsung_get_tin_rate(chip, chan);
 189         dev_dbg(chip->chip.dev, "tin parent at %lu\n", rate);
 190 
 191         /*
 192          * Compare minimum PWM frequency that can be achieved with possible
 193          * divider settings and choose the lowest divisor that can generate
 194          * frequencies lower than requested.
 195          */
 196         if (variant->bits < 32) {
 197                 /* Only for s3c24xx */
 198                 for (div = variant->div_base; div < 4; ++div)
 199                         if ((rate >> (variant->bits + div)) < freq)
 200                                 break;
 201         } else {
 202                 /*
 203                  * Other variants have enough counter bits to generate any
 204                  * requested rate, so no need to check higher divisors.
 205                  */
 206                 div = variant->div_base;
 207         }
 208 
 209         pwm_samsung_set_divisor(chip, chan, BIT(div));
 210 
 211         return rate >> div;
 212 }
 213 
 214 static int pwm_samsung_request(struct pwm_chip *chip, struct pwm_device *pwm)
 215 {
 216         struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 217         struct samsung_pwm_channel *our_chan;
 218 
 219         if (!(our_chip->variant.output_mask & BIT(pwm->hwpwm))) {
 220                 dev_warn(chip->dev,
 221                         "tried to request PWM channel %d without output\n",
 222                         pwm->hwpwm);
 223                 return -EINVAL;
 224         }
 225 
 226         our_chan = kzalloc(sizeof(*our_chan), GFP_KERNEL);
 227         if (!our_chan)
 228                 return -ENOMEM;
 229 
 230         pwm_set_chip_data(pwm, our_chan);
 231 
 232         return 0;
 233 }
 234 
 235 static void pwm_samsung_free(struct pwm_chip *chip, struct pwm_device *pwm)
 236 {
 237         kfree(pwm_get_chip_data(pwm));
 238 }
 239 
 240 static int pwm_samsung_enable(struct pwm_chip *chip, struct pwm_device *pwm)
 241 {
 242         struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 243         unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
 244         unsigned long flags;
 245         u32 tcon;
 246 
 247         spin_lock_irqsave(&samsung_pwm_lock, flags);
 248 
 249         tcon = readl(our_chip->base + REG_TCON);
 250 
 251         tcon &= ~TCON_START(tcon_chan);
 252         tcon |= TCON_MANUALUPDATE(tcon_chan);
 253         writel(tcon, our_chip->base + REG_TCON);
 254 
 255         tcon &= ~TCON_MANUALUPDATE(tcon_chan);
 256         tcon |= TCON_START(tcon_chan) | TCON_AUTORELOAD(tcon_chan);
 257         writel(tcon, our_chip->base + REG_TCON);
 258 
 259         our_chip->disabled_mask &= ~BIT(pwm->hwpwm);
 260 
 261         spin_unlock_irqrestore(&samsung_pwm_lock, flags);
 262 
 263         return 0;
 264 }
 265 
 266 static void pwm_samsung_disable(struct pwm_chip *chip, struct pwm_device *pwm)
 267 {
 268         struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 269         unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
 270         unsigned long flags;
 271         u32 tcon;
 272 
 273         spin_lock_irqsave(&samsung_pwm_lock, flags);
 274 
 275         tcon = readl(our_chip->base + REG_TCON);
 276         tcon &= ~TCON_AUTORELOAD(tcon_chan);
 277         writel(tcon, our_chip->base + REG_TCON);
 278 
 279         our_chip->disabled_mask |= BIT(pwm->hwpwm);
 280 
 281         spin_unlock_irqrestore(&samsung_pwm_lock, flags);
 282 }
 283 
 284 static void pwm_samsung_manual_update(struct samsung_pwm_chip *chip,
 285                                       struct pwm_device *pwm)
 286 {
 287         unsigned int tcon_chan = to_tcon_channel(pwm->hwpwm);
 288         u32 tcon;
 289         unsigned long flags;
 290 
 291         spin_lock_irqsave(&samsung_pwm_lock, flags);
 292 
 293         tcon = readl(chip->base + REG_TCON);
 294         tcon |= TCON_MANUALUPDATE(tcon_chan);
 295         writel(tcon, chip->base + REG_TCON);
 296 
 297         tcon &= ~TCON_MANUALUPDATE(tcon_chan);
 298         writel(tcon, chip->base + REG_TCON);
 299 
 300         spin_unlock_irqrestore(&samsung_pwm_lock, flags);
 301 }
 302 
 303 static int __pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 304                                 int duty_ns, int period_ns, bool force_period)
 305 {
 306         struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 307         struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
 308         u32 tin_ns = chan->tin_ns, tcnt, tcmp, oldtcmp;
 309 
 310         /*
 311          * We currently avoid using 64bit arithmetic by using the
 312          * fact that anything faster than 1Hz is easily representable
 313          * by 32bits.
 314          */
 315         if (period_ns > NSEC_PER_SEC)
 316                 return -ERANGE;
 317 
 318         tcnt = readl(our_chip->base + REG_TCNTB(pwm->hwpwm));
 319         oldtcmp = readl(our_chip->base + REG_TCMPB(pwm->hwpwm));
 320 
 321         /* We need tick count for calculation, not last tick. */
 322         ++tcnt;
 323 
 324         /* Check to see if we are changing the clock rate of the PWM. */
 325         if (chan->period_ns != period_ns || force_period) {
 326                 unsigned long tin_rate;
 327                 u32 period;
 328 
 329                 period = NSEC_PER_SEC / period_ns;
 330 
 331                 dev_dbg(our_chip->chip.dev, "duty_ns=%d, period_ns=%d (%u)\n",
 332                                                 duty_ns, period_ns, period);
 333 
 334                 tin_rate = pwm_samsung_calc_tin(our_chip, pwm->hwpwm, period);
 335 
 336                 dev_dbg(our_chip->chip.dev, "tin_rate=%lu\n", tin_rate);
 337 
 338                 tin_ns = NSEC_PER_SEC / tin_rate;
 339                 tcnt = period_ns / tin_ns;
 340         }
 341 
 342         /* Period is too short. */
 343         if (tcnt <= 1)
 344                 return -ERANGE;
 345 
 346         /* Note that counters count down. */
 347         tcmp = duty_ns / tin_ns;
 348 
 349         /* 0% duty is not available */
 350         if (!tcmp)
 351                 ++tcmp;
 352 
 353         tcmp = tcnt - tcmp;
 354 
 355         /* Decrement to get tick numbers, instead of tick counts. */
 356         --tcnt;
 357         /* -1UL will give 100% duty. */
 358         --tcmp;
 359 
 360         dev_dbg(our_chip->chip.dev,
 361                                 "tin_ns=%u, tcmp=%u/%u\n", tin_ns, tcmp, tcnt);
 362 
 363         /* Update PWM registers. */
 364         writel(tcnt, our_chip->base + REG_TCNTB(pwm->hwpwm));
 365         writel(tcmp, our_chip->base + REG_TCMPB(pwm->hwpwm));
 366 
 367         /*
 368          * In case the PWM is currently at 100% duty cycle, force a manual
 369          * update to prevent the signal staying high if the PWM is disabled
 370          * shortly afer this update (before it autoreloaded the new values).
 371          */
 372         if (oldtcmp == (u32) -1) {
 373                 dev_dbg(our_chip->chip.dev, "Forcing manual update");
 374                 pwm_samsung_manual_update(our_chip, pwm);
 375         }
 376 
 377         chan->period_ns = period_ns;
 378         chan->tin_ns = tin_ns;
 379         chan->duty_ns = duty_ns;
 380 
 381         return 0;
 382 }
 383 
 384 static int pwm_samsung_config(struct pwm_chip *chip, struct pwm_device *pwm,
 385                               int duty_ns, int period_ns)
 386 {
 387         return __pwm_samsung_config(chip, pwm, duty_ns, period_ns, false);
 388 }
 389 
 390 static void pwm_samsung_set_invert(struct samsung_pwm_chip *chip,
 391                                    unsigned int channel, bool invert)
 392 {
 393         unsigned int tcon_chan = to_tcon_channel(channel);
 394         unsigned long flags;
 395         u32 tcon;
 396 
 397         spin_lock_irqsave(&samsung_pwm_lock, flags);
 398 
 399         tcon = readl(chip->base + REG_TCON);
 400 
 401         if (invert) {
 402                 chip->inverter_mask |= BIT(channel);
 403                 tcon |= TCON_INVERT(tcon_chan);
 404         } else {
 405                 chip->inverter_mask &= ~BIT(channel);
 406                 tcon &= ~TCON_INVERT(tcon_chan);
 407         }
 408 
 409         writel(tcon, chip->base + REG_TCON);
 410 
 411         spin_unlock_irqrestore(&samsung_pwm_lock, flags);
 412 }
 413 
 414 static int pwm_samsung_set_polarity(struct pwm_chip *chip,
 415                                     struct pwm_device *pwm,
 416                                     enum pwm_polarity polarity)
 417 {
 418         struct samsung_pwm_chip *our_chip = to_samsung_pwm_chip(chip);
 419         bool invert = (polarity == PWM_POLARITY_NORMAL);
 420 
 421         /* Inverted means normal in the hardware. */
 422         pwm_samsung_set_invert(our_chip, pwm->hwpwm, invert);
 423 
 424         return 0;
 425 }
 426 
 427 static const struct pwm_ops pwm_samsung_ops = {
 428         .request        = pwm_samsung_request,
 429         .free           = pwm_samsung_free,
 430         .enable         = pwm_samsung_enable,
 431         .disable        = pwm_samsung_disable,
 432         .config         = pwm_samsung_config,
 433         .set_polarity   = pwm_samsung_set_polarity,
 434         .owner          = THIS_MODULE,
 435 };
 436 
 437 #ifdef CONFIG_OF
 438 static const struct samsung_pwm_variant s3c24xx_variant = {
 439         .bits           = 16,
 440         .div_base       = 1,
 441         .has_tint_cstat = false,
 442         .tclk_mask      = BIT(4),
 443 };
 444 
 445 static const struct samsung_pwm_variant s3c64xx_variant = {
 446         .bits           = 32,
 447         .div_base       = 0,
 448         .has_tint_cstat = true,
 449         .tclk_mask      = BIT(7) | BIT(6) | BIT(5),
 450 };
 451 
 452 static const struct samsung_pwm_variant s5p64x0_variant = {
 453         .bits           = 32,
 454         .div_base       = 0,
 455         .has_tint_cstat = true,
 456         .tclk_mask      = 0,
 457 };
 458 
 459 static const struct samsung_pwm_variant s5pc100_variant = {
 460         .bits           = 32,
 461         .div_base       = 0,
 462         .has_tint_cstat = true,
 463         .tclk_mask      = BIT(5),
 464 };
 465 
 466 static const struct of_device_id samsung_pwm_matches[] = {
 467         { .compatible = "samsung,s3c2410-pwm", .data = &s3c24xx_variant },
 468         { .compatible = "samsung,s3c6400-pwm", .data = &s3c64xx_variant },
 469         { .compatible = "samsung,s5p6440-pwm", .data = &s5p64x0_variant },
 470         { .compatible = "samsung,s5pc100-pwm", .data = &s5pc100_variant },
 471         { .compatible = "samsung,exynos4210-pwm", .data = &s5p64x0_variant },
 472         {},
 473 };
 474 MODULE_DEVICE_TABLE(of, samsung_pwm_matches);
 475 
 476 static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
 477 {
 478         struct device_node *np = chip->chip.dev->of_node;
 479         const struct of_device_id *match;
 480         struct property *prop;
 481         const __be32 *cur;
 482         u32 val;
 483 
 484         match = of_match_node(samsung_pwm_matches, np);
 485         if (!match)
 486                 return -ENODEV;
 487 
 488         memcpy(&chip->variant, match->data, sizeof(chip->variant));
 489 
 490         of_property_for_each_u32(np, "samsung,pwm-outputs", prop, cur, val) {
 491                 if (val >= SAMSUNG_PWM_NUM) {
 492                         dev_err(chip->chip.dev,
 493                                 "%s: invalid channel index in samsung,pwm-outputs property\n",
 494                                                                 __func__);
 495                         continue;
 496                 }
 497                 chip->variant.output_mask |= BIT(val);
 498         }
 499 
 500         return 0;
 501 }
 502 #else
 503 static int pwm_samsung_parse_dt(struct samsung_pwm_chip *chip)
 504 {
 505         return -ENODEV;
 506 }
 507 #endif
 508 
 509 static int pwm_samsung_probe(struct platform_device *pdev)
 510 {
 511         struct device *dev = &pdev->dev;
 512         struct samsung_pwm_chip *chip;
 513         struct resource *res;
 514         unsigned int chan;
 515         int ret;
 516 
 517         chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
 518         if (chip == NULL)
 519                 return -ENOMEM;
 520 
 521         chip->chip.dev = &pdev->dev;
 522         chip->chip.ops = &pwm_samsung_ops;
 523         chip->chip.base = -1;
 524         chip->chip.npwm = SAMSUNG_PWM_NUM;
 525         chip->inverter_mask = BIT(SAMSUNG_PWM_NUM) - 1;
 526 
 527         if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
 528                 ret = pwm_samsung_parse_dt(chip);
 529                 if (ret)
 530                         return ret;
 531 
 532                 chip->chip.of_xlate = of_pwm_xlate_with_flags;
 533                 chip->chip.of_pwm_n_cells = 3;
 534         } else {
 535                 if (!pdev->dev.platform_data) {
 536                         dev_err(&pdev->dev, "no platform data specified\n");
 537                         return -EINVAL;
 538                 }
 539 
 540                 memcpy(&chip->variant, pdev->dev.platform_data,
 541                                                         sizeof(chip->variant));
 542         }
 543 
 544         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 545         chip->base = devm_ioremap_resource(&pdev->dev, res);
 546         if (IS_ERR(chip->base))
 547                 return PTR_ERR(chip->base);
 548 
 549         chip->base_clk = devm_clk_get(&pdev->dev, "timers");
 550         if (IS_ERR(chip->base_clk)) {
 551                 dev_err(dev, "failed to get timer base clk\n");
 552                 return PTR_ERR(chip->base_clk);
 553         }
 554 
 555         ret = clk_prepare_enable(chip->base_clk);
 556         if (ret < 0) {
 557                 dev_err(dev, "failed to enable base clock\n");
 558                 return ret;
 559         }
 560 
 561         for (chan = 0; chan < SAMSUNG_PWM_NUM; ++chan)
 562                 if (chip->variant.output_mask & BIT(chan))
 563                         pwm_samsung_set_invert(chip, chan, true);
 564 
 565         /* Following clocks are optional. */
 566         chip->tclk0 = devm_clk_get(&pdev->dev, "pwm-tclk0");
 567         chip->tclk1 = devm_clk_get(&pdev->dev, "pwm-tclk1");
 568 
 569         platform_set_drvdata(pdev, chip);
 570 
 571         ret = pwmchip_add(&chip->chip);
 572         if (ret < 0) {
 573                 dev_err(dev, "failed to register PWM chip\n");
 574                 clk_disable_unprepare(chip->base_clk);
 575                 return ret;
 576         }
 577 
 578         dev_dbg(dev, "base_clk at %lu, tclk0 at %lu, tclk1 at %lu\n",
 579                 clk_get_rate(chip->base_clk),
 580                 !IS_ERR(chip->tclk0) ? clk_get_rate(chip->tclk0) : 0,
 581                 !IS_ERR(chip->tclk1) ? clk_get_rate(chip->tclk1) : 0);
 582 
 583         return 0;
 584 }
 585 
 586 static int pwm_samsung_remove(struct platform_device *pdev)
 587 {
 588         struct samsung_pwm_chip *chip = platform_get_drvdata(pdev);
 589         int ret;
 590 
 591         ret = pwmchip_remove(&chip->chip);
 592         if (ret < 0)
 593                 return ret;
 594 
 595         clk_disable_unprepare(chip->base_clk);
 596 
 597         return 0;
 598 }
 599 
 600 #ifdef CONFIG_PM_SLEEP
 601 static int pwm_samsung_resume(struct device *dev)
 602 {
 603         struct samsung_pwm_chip *our_chip = dev_get_drvdata(dev);
 604         struct pwm_chip *chip = &our_chip->chip;
 605         unsigned int i;
 606 
 607         for (i = 0; i < SAMSUNG_PWM_NUM; i++) {
 608                 struct pwm_device *pwm = &chip->pwms[i];
 609                 struct samsung_pwm_channel *chan = pwm_get_chip_data(pwm);
 610 
 611                 if (!chan)
 612                         continue;
 613 
 614                 if (our_chip->variant.output_mask & BIT(i))
 615                         pwm_samsung_set_invert(our_chip, i,
 616                                         our_chip->inverter_mask & BIT(i));
 617 
 618                 if (chan->period_ns) {
 619                         __pwm_samsung_config(chip, pwm, chan->duty_ns,
 620                                              chan->period_ns, true);
 621                         /* needed to make PWM disable work on Odroid-XU3 */
 622                         pwm_samsung_manual_update(our_chip, pwm);
 623                 }
 624 
 625                 if (our_chip->disabled_mask & BIT(i))
 626                         pwm_samsung_disable(chip, pwm);
 627                 else
 628                         pwm_samsung_enable(chip, pwm);
 629         }
 630 
 631         return 0;
 632 }
 633 #endif
 634 
 635 static SIMPLE_DEV_PM_OPS(pwm_samsung_pm_ops, NULL, pwm_samsung_resume);
 636 
 637 static struct platform_driver pwm_samsung_driver = {
 638         .driver         = {
 639                 .name   = "samsung-pwm",
 640                 .pm     = &pwm_samsung_pm_ops,
 641                 .of_match_table = of_match_ptr(samsung_pwm_matches),
 642         },
 643         .probe          = pwm_samsung_probe,
 644         .remove         = pwm_samsung_remove,
 645 };
 646 module_platform_driver(pwm_samsung_driver);
 647 
 648 MODULE_LICENSE("GPL");
 649 MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
 650 MODULE_ALIAS("platform:samsung-pwm");

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