Merge tag 'for-3.9-rc1' of git://gitorious.org/linux-pwm/linux-pwm
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Feb 2013 17:34:29 +0000 (09:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 26 Feb 2013 17:34:29 +0000 (09:34 -0800)
Pull PWM changes from Thierry Reding:
 "A new driver has been added to support the PWM mode of the timer
  counter blocks found on Atmel AT91 SoCs.  The VT8500 driver now
  supports changing the PWM signal polarity and the TI drivers (EHRPWM
  and ECAP) gained suspend and resume functionality.

  User drivers can now query the core for whether access to a PWM device
  will sleep (if the PWM chip is on a slow bus such as I2C or SPI).

  The pwm-backlight driver now handles the backlight BL_CORE_FBBLANK
  state in addition to the FB layer's blanking states.

  To round things off, a few fixes and cleanups are also included"

* tag 'for-3.9-rc1' of git://gitorious.org/linux-pwm/linux-pwm:
  pwm: twl: Use to_twl() instead of container_of()
  pwm: tegra: assume CONFIG_OF
  pwm_backlight: Validate dft_brightness in main probe function
  pwm: Export pwm_{set,get}_chip_data()
  pwm: Make Kconfig entries more consistent
  pwm: Add can_sleep property to drivers
  pwm: Add pwm_can_sleep() as exported API to users
  pwm-backlight: handle BL_CORE_FBBLANK state
  pwm: pwm-tiecap: Low power sleep support
  pwm: pwm-tiehrpwm: Low power sleep support
  pwm: pwm-tiehrpwm: Update the clock handling of pwm-tiehrpwm driver
  pwm: vt8500: Add polarity support
  pwm: vt8500: Register write busy test performed incorrectly
  pwm: atmel: add Timer Counter Block PWM driver

1  2 
drivers/pwm/core.c
drivers/pwm/pwm-tegra.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/pwm-vt8500.c
drivers/video/backlight/pwm_bl.c
include/linux/pwm.h

diff --combined drivers/pwm/core.c
@@@ -211,6 -211,7 +211,7 @@@ int pwm_set_chip_data(struct pwm_devic
  
        return 0;
  }
+ EXPORT_SYMBOL_GPL(pwm_set_chip_data);
  
  /**
   * pwm_get_chip_data() - get private chip data for a PWM
@@@ -220,6 -221,7 +221,7 @@@ void *pwm_get_chip_data(struct pwm_devi
  {
        return pwm ? pwm->chip_data : NULL;
  }
+ EXPORT_SYMBOL_GPL(pwm_get_chip_data);
  
  /**
   * pwmchip_add() - register a new PWM chip
@@@ -471,7 -473,7 +473,7 @@@ static struct pwm_chip *of_node_to_pwmc
  }
  
  /**
 - * of_pwm_request() - request a PWM via the PWM framework
 + * of_pwm_get() - request a PWM via the PWM framework
   * @np: device node to get the PWM from
   * @con_id: consumer name
   *
   * becomes mandatory for devices that look up the PWM device via the con_id
   * parameter.
   */
 -static struct pwm_device *of_pwm_request(struct device_node *np,
 -                                       const char *con_id)
 +struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id)
  {
        struct pwm_device *pwm = NULL;
        struct of_phandle_args args;
@@@ -544,7 -547,6 +546,7 @@@ put
  
        return pwm;
  }
 +EXPORT_SYMBOL_GPL(of_pwm_get);
  
  /**
   * pwm_add_table() - register PWM device consumers
@@@ -587,7 -589,7 +589,7 @@@ struct pwm_device *pwm_get(struct devic
  
        /* look up via DT first */
        if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
 -              return of_pwm_request(dev->of_node, con_id);
 +              return of_pwm_get(dev->of_node, con_id);
  
        /*
         * We look up the provider in the static table typically provided by
@@@ -708,36 -710,6 +710,36 @@@ struct pwm_device *devm_pwm_get(struct 
  }
  EXPORT_SYMBOL_GPL(devm_pwm_get);
  
 +/**
 + * devm_of_pwm_get() - resource managed of_pwm_get()
 + * @dev: device for PWM consumer
 + * @np: device node to get the PWM from
 + * @con_id: consumer name
 + *
 + * This function performs like of_pwm_get() but the acquired PWM device will
 + * automatically be released on driver detach.
 + */
 +struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
 +                                 const char *con_id)
 +{
 +      struct pwm_device **ptr, *pwm;
 +
 +      ptr = devres_alloc(devm_pwm_release, sizeof(**ptr), GFP_KERNEL);
 +      if (!ptr)
 +              return ERR_PTR(-ENOMEM);
 +
 +      pwm = of_pwm_get(np, con_id);
 +      if (!IS_ERR(pwm)) {
 +              *ptr = pwm;
 +              devres_add(dev, ptr);
 +      } else {
 +              devres_free(ptr);
 +      }
 +
 +      return pwm;
 +}
 +EXPORT_SYMBOL_GPL(devm_of_pwm_get);
 +
  static int devm_pwm_match(struct device *dev, void *res, void *data)
  {
        struct pwm_device **p = res;
@@@ -763,6 -735,18 +765,18 @@@ void devm_pwm_put(struct device *dev, s
  }
  EXPORT_SYMBOL_GPL(devm_pwm_put);
  
+ /**
+   * pwm_can_sleep() - report whether PWM access will sleep
+   * @pwm: PWM device
+   *
+   * It returns true if accessing the PWM can sleep, false otherwise.
+   */
+ bool pwm_can_sleep(struct pwm_device *pwm)
+ {
+       return pwm->chip->can_sleep;
+ }
+ EXPORT_SYMBOL_GPL(pwm_can_sleep);
  #ifdef CONFIG_DEBUG_FS
  static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
  {
diff --combined drivers/pwm/pwm-tegra.c
@@@ -186,9 -186,9 +186,9 @@@ static int tegra_pwm_probe(struct platf
                return -ENODEV;
        }
  
 -      pwm->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
 -      if (!pwm->mmio_base)
 -              return -EADDRNOTAVAIL;
 +      pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
 +      if (IS_ERR(pwm->mmio_base))
 +              return PTR_ERR(pwm->mmio_base);
  
        platform_set_drvdata(pdev, pwm);
  
@@@ -233,7 -233,6 +233,6 @@@ static int tegra_pwm_remove(struct plat
        return pwmchip_remove(&pc->chip);
  }
  
- #ifdef CONFIG_OF
  static struct of_device_id tegra_pwm_of_match[] = {
        { .compatible = "nvidia,tegra20-pwm" },
        { .compatible = "nvidia,tegra30-pwm" },
  };
  
  MODULE_DEVICE_TABLE(of, tegra_pwm_of_match);
- #endif
  
  static struct platform_driver tegra_pwm_driver = {
        .driver = {
                .name = "tegra-pwm",
-               .of_match_table = of_match_ptr(tegra_pwm_of_match),
+               .of_match_table = tegra_pwm_of_match,
        },
        .probe = tegra_pwm_probe,
        .remove = tegra_pwm_remove,
diff --combined drivers/pwm/pwm-tiecap.c
  #define ECCTL2_SYNC_SEL_DISA  (BIT(7) | BIT(6))
  #define ECCTL2_TSCTR_FREERUN  BIT(4)
  
+ struct ecap_context {
+       u32     cap3;
+       u32     cap4;
+       u16     ecctl2;
+ };
  struct ecap_pwm_chip {
        struct pwm_chip chip;
        unsigned int    clk_rate;
        void __iomem    *mmio_base;
+       struct ecap_context ctx;
  };
  
  static inline struct ecap_pwm_chip *to_ecap_pwm_chip(struct pwm_chip *chip)
@@@ -238,9 -245,9 +245,9 @@@ static int ecap_pwm_probe(struct platfo
                return -ENODEV;
        }
  
 -      pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
 -      if (!pc->mmio_base)
 -              return -EADDRNOTAVAIL;
 +      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
 +      if (IS_ERR(pc->mmio_base))
 +              return PTR_ERR(pc->mmio_base);
  
        ret = pwmchip_add(&pc->chip);
        if (ret < 0) {
@@@ -288,11 -295,57 +295,57 @@@ static int ecap_pwm_remove(struct platf
        return pwmchip_remove(&pc->chip);
  }
  
+ void ecap_pwm_save_context(struct ecap_pwm_chip *pc)
+ {
+       pm_runtime_get_sync(pc->chip.dev);
+       pc->ctx.ecctl2 = readw(pc->mmio_base + ECCTL2);
+       pc->ctx.cap4 = readl(pc->mmio_base + CAP4);
+       pc->ctx.cap3 = readl(pc->mmio_base + CAP3);
+       pm_runtime_put_sync(pc->chip.dev);
+ }
+ void ecap_pwm_restore_context(struct ecap_pwm_chip *pc)
+ {
+       writel(pc->ctx.cap3, pc->mmio_base + CAP3);
+       writel(pc->ctx.cap4, pc->mmio_base + CAP4);
+       writew(pc->ctx.ecctl2, pc->mmio_base + ECCTL2);
+ }
+ static int ecap_pwm_suspend(struct device *dev)
+ {
+       struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
+       struct pwm_device *pwm = pc->chip.pwms;
+       ecap_pwm_save_context(pc);
+       /* Disable explicitly if PWM is running */
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               pm_runtime_put_sync(dev);
+       return 0;
+ }
+ static int ecap_pwm_resume(struct device *dev)
+ {
+       struct ecap_pwm_chip *pc = dev_get_drvdata(dev);
+       struct pwm_device *pwm = pc->chip.pwms;
+       /* Enable explicitly if PWM was running */
+       if (test_bit(PWMF_ENABLED, &pwm->flags))
+               pm_runtime_get_sync(dev);
+       ecap_pwm_restore_context(pc);
+       return 0;
+ }
+ static SIMPLE_DEV_PM_OPS(ecap_pwm_pm_ops, ecap_pwm_suspend, ecap_pwm_resume);
  static struct platform_driver ecap_pwm_driver = {
        .driver = {
                .name   = "ecap",
                .owner  = THIS_MODULE,
                .of_match_table = ecap_of_match,
+               .pm     = &ecap_pwm_pm_ops,
        },
        .probe = ecap_pwm_probe,
        .remove = ecap_pwm_remove,
  
  #define NUM_PWM_CHANNEL               2       /* EHRPWM channels */
  
+ struct ehrpwm_context {
+       u16 tbctl;
+       u16 tbprd;
+       u16 cmpa;
+       u16 cmpb;
+       u16 aqctla;
+       u16 aqctlb;
+       u16 aqsfrc;
+       u16 aqcsfrc;
+ };
  struct ehrpwm_pwm_chip {
        struct pwm_chip chip;
        unsigned int    clk_rate;
        unsigned long period_cycles[NUM_PWM_CHANNEL];
        enum pwm_polarity polarity[NUM_PWM_CHANNEL];
        struct  clk     *tbclk;
+       struct ehrpwm_context ctx;
  };
  
  static inline struct ehrpwm_pwm_chip *to_ehrpwm_pwm_chip(struct pwm_chip *chip)
        return container_of(chip, struct ehrpwm_pwm_chip, chip);
  }
  
+ static u16 ehrpwm_read(void *base, int offset)
+ {
+       return readw(base + offset);
+ }
  static void ehrpwm_write(void *base, int offset, unsigned int val)
  {
        writew(val & 0xFFFF, base + offset);
@@@ -318,6 -335,7 +335,7 @@@ static int ehrpwm_pwm_enable(struct pwm
  {
        struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip);
        unsigned short aqcsfrc_val, aqcsfrc_mask;
+       int ret;
  
        /* Leave clock enabled on enabling PWM */
        pm_runtime_get_sync(chip->dev);
        configure_polarity(pc, pwm->hwpwm);
  
        /* Enable TBCLK before enabling PWM device */
-       clk_enable(pc->tbclk);
+       ret = clk_prepare_enable(pc->tbclk);
+       if (ret) {
+               pr_err("Failed to enable TBCLK for %s\n",
+                               dev_name(pc->chip.dev));
+               return ret;
+       }
  
        /* Enable time counter for free_run */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN);
@@@ -372,7 -395,7 +395,7 @@@ static void ehrpwm_pwm_disable(struct p
        ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val);
  
        /* Disabling TBCLK on PWM disable */
-       clk_disable(pc->tbclk);
+       clk_disable_unprepare(pc->tbclk);
  
        /* Stop Time base counter */
        ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT);
@@@ -453,9 -476,9 +476,9 @@@ static int ehrpwm_pwm_probe(struct plat
                return -ENODEV;
        }
  
 -      pc->mmio_base = devm_request_and_ioremap(&pdev->dev, r);
 -      if (!pc->mmio_base)
 -              return  -EADDRNOTAVAIL;
 +      pc->mmio_base = devm_ioremap_resource(&pdev->dev, r);
 +      if (IS_ERR(pc->mmio_base))
 +              return PTR_ERR(pc->mmio_base);
  
        /* Acquire tbclk for Time Base EHRPWM submodule */
        pc->tbclk = devm_clk_get(&pdev->dev, "tbclk");
@@@ -510,11 -533,77 +533,77 @@@ static int ehrpwm_pwm_remove(struct pla
        return pwmchip_remove(&pc->chip);
  }
  
+ void ehrpwm_pwm_save_context(struct ehrpwm_pwm_chip *pc)
+ {
+       pm_runtime_get_sync(pc->chip.dev);
+       pc->ctx.tbctl = ehrpwm_read(pc->mmio_base, TBCTL);
+       pc->ctx.tbprd = ehrpwm_read(pc->mmio_base, TBPRD);
+       pc->ctx.cmpa = ehrpwm_read(pc->mmio_base, CMPA);
+       pc->ctx.cmpb = ehrpwm_read(pc->mmio_base, CMPB);
+       pc->ctx.aqctla = ehrpwm_read(pc->mmio_base, AQCTLA);
+       pc->ctx.aqctlb = ehrpwm_read(pc->mmio_base, AQCTLB);
+       pc->ctx.aqsfrc = ehrpwm_read(pc->mmio_base, AQSFRC);
+       pc->ctx.aqcsfrc = ehrpwm_read(pc->mmio_base, AQCSFRC);
+       pm_runtime_put_sync(pc->chip.dev);
+ }
+ void ehrpwm_pwm_restore_context(struct ehrpwm_pwm_chip *pc)
+ {
+       ehrpwm_write(pc->mmio_base, TBPRD, pc->ctx.tbprd);
+       ehrpwm_write(pc->mmio_base, CMPA, pc->ctx.cmpa);
+       ehrpwm_write(pc->mmio_base, CMPB, pc->ctx.cmpb);
+       ehrpwm_write(pc->mmio_base, AQCTLA, pc->ctx.aqctla);
+       ehrpwm_write(pc->mmio_base, AQCTLB, pc->ctx.aqctlb);
+       ehrpwm_write(pc->mmio_base, AQSFRC, pc->ctx.aqsfrc);
+       ehrpwm_write(pc->mmio_base, AQCSFRC, pc->ctx.aqcsfrc);
+       ehrpwm_write(pc->mmio_base, TBCTL, pc->ctx.tbctl);
+ }
+ static int ehrpwm_pwm_suspend(struct device *dev)
+ {
+       struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
+       int i;
+       ehrpwm_pwm_save_context(pc);
+       for (i = 0; i < pc->chip.npwm; i++) {
+               struct pwm_device *pwm = &pc->chip.pwms[i];
+               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+                       continue;
+               /* Disable explicitly if PWM is running */
+               pm_runtime_put_sync(dev);
+       }
+       return 0;
+ }
+ static int ehrpwm_pwm_resume(struct device *dev)
+ {
+       struct ehrpwm_pwm_chip *pc = dev_get_drvdata(dev);
+       int i;
+       for (i = 0; i < pc->chip.npwm; i++) {
+               struct pwm_device *pwm = &pc->chip.pwms[i];
+               if (!test_bit(PWMF_ENABLED, &pwm->flags))
+                       continue;
+               /* Enable explicitly if PWM was running */
+               pm_runtime_get_sync(dev);
+       }
+       ehrpwm_pwm_restore_context(pc);
+       return 0;
+ }
+ static SIMPLE_DEV_PM_OPS(ehrpwm_pwm_pm_ops, ehrpwm_pwm_suspend,
+               ehrpwm_pwm_resume);
  static struct platform_driver ehrpwm_pwm_driver = {
        .driver = {
                .name   = "ehrpwm",
                .owner  = THIS_MODULE,
                .of_match_table = ehrpwm_of_match,
+               .pm     = &ehrpwm_pwm_pm_ops,
        },
        .probe = ehrpwm_pwm_probe,
        .remove = ehrpwm_pwm_remove,
diff --combined drivers/pwm/pwm-vt8500.c
   */
  #define VT8500_NR_PWMS        2
  
+ #define REG_CTRL(pwm)         (((pwm) << 4) + 0x00)
+ #define REG_SCALAR(pwm)               (((pwm) << 4) + 0x04)
+ #define REG_PERIOD(pwm)               (((pwm) << 4) + 0x08)
+ #define REG_DUTY(pwm)         (((pwm) << 4) + 0x0C)
+ #define REG_STATUS            0x40
+ #define CTRL_ENABLE           BIT(0)
+ #define CTRL_INVERT           BIT(1)
+ #define CTRL_AUTOLOAD         BIT(2)
+ #define CTRL_STOP_IMM         BIT(3)
+ #define CTRL_LOAD_PRESCALE    BIT(4)
+ #define CTRL_LOAD_PERIOD      BIT(5)
+ #define STATUS_CTRL_UPDATE    BIT(0)
+ #define STATUS_SCALAR_UPDATE  BIT(1)
+ #define STATUS_PERIOD_UPDATE  BIT(2)
+ #define STATUS_DUTY_UPDATE    BIT(3)
+ #define STATUS_ALL_UPDATE     0x0F
  struct vt8500_chip {
        struct pwm_chip chip;
        void __iomem *base;
  #define to_vt8500_chip(chip)  container_of(chip, struct vt8500_chip, chip)
  
  #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
- static inline void pwm_busy_wait(void __iomem *reg, u8 bitmask)
+ static inline void pwm_busy_wait(struct vt8500_chip *vt8500, int nr, u8 bitmask)
  {
        int loops = msecs_to_loops(10);
-       while ((readb(reg) & bitmask) && --loops)
+       u32 mask = bitmask << (nr << 8);
+       while ((readl(vt8500->base + REG_STATUS) & mask) && --loops)
                cpu_relax();
  
        if (unlikely(!loops))
-               pr_warn("Waiting for status bits 0x%x to clear timed out\n",
-                          bitmask);
+               dev_warn(vt8500->chip.dev, "Waiting for status bits 0x%x to clear timed out\n",
+                        mask);
  }
  
  static int vt8500_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
@@@ -63,6 -84,7 +84,7 @@@
        unsigned long long c;
        unsigned long period_cycles, prescale, pv, dc;
        int err;
+       u32 val;
  
        err = clk_enable(vt8500->clk);
        if (err < 0) {
        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));
+       writel(prescale, vt8500->base + REG_SCALAR(pwm->hwpwm));
+       pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_SCALAR_UPDATE);
  
-       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 2));
-       writel(pv, vt8500->base + 0x8 + (pwm->hwpwm << 4));
+       writel(pv, vt8500->base + REG_PERIOD(pwm->hwpwm));
+       pwm_busy_wait(vt8500, pwm->hwpwm, STATUS_PERIOD_UPDATE);
  
-       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 3));
-       writel(dc, vt8500->base + 0xc + (pwm->hwpwm << 4));
+       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_enable(struct pwm_chip *chip, struct pwm_device *pwm)
  {
-       int err;
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
+       int err;
+       u32 val;
  
        err = clk_enable(vt8500->clk);
        if (err < 0) {
                return err;
        }
  
-       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
-       writel(5, vt8500->base + (pwm->hwpwm << 4));
+       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;
  }
  
  static void vt8500_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
  {
        struct vt8500_chip *vt8500 = to_vt8500_chip(chip);
+       u32 val;
  
-       pwm_busy_wait(vt8500->base + 0x40 + pwm->hwpwm, (1 << 0));
-       writel(0, vt8500->base + (pwm->hwpwm << 4));
+       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_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 struct pwm_ops vt8500_pwm_ops = {
        .enable = vt8500_pwm_enable,
        .disable = vt8500_pwm_disable,
        .config = vt8500_pwm_config,
+       .set_polarity = vt8500_pwm_set_polarity,
        .owner = THIS_MODULE,
  };
  
@@@ -163,6 -218,8 +218,8 @@@ static int vt8500_pwm_probe(struct plat
  
        chip->chip.dev = &pdev->dev;
        chip->chip.ops = &vt8500_pwm_ops;
+       chip->chip.of_xlate = of_pwm_xlate_with_flags;
+       chip->chip.of_pwm_n_cells = 3;
        chip->chip.base = -1;
        chip->chip.npwm = VT8500_NR_PWMS;
  
                return -ENODEV;
        }
  
 -      chip->base = devm_request_and_ioremap(&pdev->dev, r);
 -      if (!chip->base)
 -              return -EADDRNOTAVAIL;
 +      chip->base = devm_ioremap_resource(&pdev->dev, r);
 +      if (IS_ERR(chip->base))
 +              return PTR_ERR(chip->base);
  
        ret = clk_prepare(chip->clk);
        if (ret < 0) {
@@@ -37,14 -37,13 +37,13 @@@ struct pwm_bl_data 
  
  static int pwm_backlight_update_status(struct backlight_device *bl)
  {
 -      struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 +      struct pwm_bl_data *pb = bl_get_data(bl);
        int brightness = bl->props.brightness;
        int max = bl->props.max_brightness;
  
-       if (bl->props.power != FB_BLANK_UNBLANK)
-               brightness = 0;
-       if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+       if (bl->props.power != FB_BLANK_UNBLANK ||
+           bl->props.fb_blank != FB_BLANK_UNBLANK ||
+           bl->props.state & BL_CORE_FBBLANK)
                brightness = 0;
  
        if (pb->notify)
@@@ -83,7 -82,7 +82,7 @@@ static int pwm_backlight_get_brightness
  static int pwm_backlight_check_fb(struct backlight_device *bl,
                                  struct fb_info *info)
  {
 -      struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 +      struct pwm_bl_data *pb = bl_get_data(bl);
  
        return !pb->check_fb || pb->check_fb(pb->dev, info);
  }
@@@ -135,12 -134,6 +134,6 @@@ static int pwm_backlight_parse_dt(struc
                if (ret < 0)
                        return ret;
  
-               if (value >= data->max_brightness) {
-                       dev_warn(dev, "invalid default brightness level: %u, using %u\n",
-                                value, data->max_brightness - 1);
-                       value = data->max_brightness - 1;
-               }
                data->dft_brightness = value;
                data->max_brightness--;
        }
@@@ -249,6 -242,13 +242,13 @@@ static int pwm_backlight_probe(struct p
                goto err_alloc;
        }
  
+       if (data->dft_brightness > data->max_brightness) {
+               dev_warn(&pdev->dev,
+                        "invalid default brightness level: %u, using %u\n",
+                        data->dft_brightness, data->max_brightness);
+               data->dft_brightness = data->max_brightness;
+       }
        bl->props.brightness = data->dft_brightness;
        backlight_update_status(bl);
  
@@@ -264,7 -264,7 +264,7 @@@ err_alloc
  static int pwm_backlight_remove(struct platform_device *pdev)
  {
        struct backlight_device *bl = platform_get_drvdata(pdev);
 -      struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 +      struct pwm_bl_data *pb = bl_get_data(bl);
  
        backlight_device_unregister(bl);
        pwm_config(pb->pwm, 0, pb->period);
  static int pwm_backlight_suspend(struct device *dev)
  {
        struct backlight_device *bl = dev_get_drvdata(dev);
 -      struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
 +      struct pwm_bl_data *pb = bl_get_data(bl);
  
        if (pb->notify)
                pb->notify(pb->dev, 0);
diff --combined include/linux/pwm.h
@@@ -146,6 -146,8 +146,8 @@@ struct pwm_ops 
   * @base: number of first PWM controlled by this chip
   * @npwm: number of PWMs controlled by this chip
   * @pwms: array of PWM devices allocated by the framework
+  * @can_sleep: must be true if the .config(), .enable() or .disable()
+  *             operations may sleep
   */
  struct pwm_chip {
        struct device           *dev;
        struct pwm_device *     (*of_xlate)(struct pwm_chip *pc,
                                            const struct of_phandle_args *args);
        unsigned int            of_pwm_n_cells;
+       bool                    can_sleep;
  };
  
  #if IS_ENABLED(CONFIG_PWM)
@@@ -174,14 -177,13 +177,16 @@@ struct pwm_device *pwm_request_from_chi
  struct pwm_device *of_pwm_xlate_with_flags(struct pwm_chip *pc,
                const struct of_phandle_args *args);
  
 -struct pwm_device *pwm_get(struct device *dev, const char *consumer);
 +struct pwm_device *pwm_get(struct device *dev, const char *con_id);
 +struct pwm_device *of_pwm_get(struct device_node *np, const char *con_id);
  void pwm_put(struct pwm_device *pwm);
  
 -struct pwm_device *devm_pwm_get(struct device *dev, const char *consumer);
 +struct pwm_device *devm_pwm_get(struct device *dev, const char *con_id);
 +struct pwm_device *devm_of_pwm_get(struct device *dev, struct device_node *np,
 +                                 const char *con_id);
  void devm_pwm_put(struct device *dev, struct pwm_device *pwm);
+ bool pwm_can_sleep(struct pwm_device *pwm);
  #else
  static inline int pwm_set_chip_data(struct pwm_device *pwm, void *data)
  {
@@@ -216,12 -218,6 +221,12 @@@ static inline struct pwm_device *pwm_ge
        return ERR_PTR(-ENODEV);
  }
  
 +static inline struct pwm_device *of_pwm_get(struct device_node *np,
 +                                          const char *con_id)
 +{
 +      return ERR_PTR(-ENODEV);
 +}
 +
  static inline void pwm_put(struct pwm_device *pwm)
  {
  }
@@@ -232,16 -228,14 +237,21 @@@ static inline struct pwm_device *devm_p
        return ERR_PTR(-ENODEV);
  }
  
 +static inline struct pwm_device *devm_of_pwm_get(struct device *dev,
 +                                               struct device_node *np,
 +                                               const char *con_id)
 +{
 +      return ERR_PTR(-ENODEV);
 +}
 +
  static inline void devm_pwm_put(struct device *dev, struct pwm_device *pwm)
  {
  }
+ static inline bool pwm_can_sleep(struct pwm_device *pwm)
+ {
+       return false;
+ }
  #endif
  
  struct pwm_lookup {