Merge branch 'timers/drivers/timer-ti-dm' into timers/drivers/next
authorDaniel Lezcano <daniel.lezcano@linaro.org>
Mon, 16 Mar 2020 12:24:10 +0000 (13:24 +0100)
committerDaniel Lezcano <daniel.lezcano@linaro.org>
Mon, 16 Mar 2020 12:24:10 +0000 (13:24 +0100)
1  2 
drivers/clocksource/timer-ti-dm.c

@@@ -1,3 -1,4 +1,4 @@@
+ // SPDX-License-Identifier: GPL-2.0+
  /*
   * linux/arch/arm/plat-omap/dmtimer.c
   *
   *
   * Copyright (C) 2009 Texas Instruments
   * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
-  *
-  * This program is free software; you can redistribute it and/or modify it
-  * under the terms of the GNU General Public License as published by the
-  * Free Software Foundation; either version 2 of the License, or (at your
-  * option) any later version.
-  *
-  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
-  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
-  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-  *
-  * You should have received a copy of the  GNU General Public License along
-  * with this program; if not, write  to the Free Software Foundation, Inc.,
-  * 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  #include <linux/clk.h>
  #include <linux/clk-provider.h>
+ #include <linux/cpu_pm.h>
  #include <linux/module.h>
  #include <linux/io.h>
  #include <linux/device.h>
@@@ -109,6 -93,47 +93,47 @@@ static void omap_timer_restore_context(
                                timer->context.tclr);
  }
  
+ static void omap_timer_save_context(struct omap_dm_timer *timer)
+ {
+       timer->context.tclr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       timer->context.twer =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG);
+       timer->context.tldr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_LOAD_REG);
+       timer->context.tmar =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_MATCH_REG);
+       timer->context.tier = readl_relaxed(timer->irq_ena);
+       timer->context.tsicr =
+                       omap_dm_timer_read_reg(timer, OMAP_TIMER_IF_CTRL_REG);
+ }
+ static int omap_timer_context_notifier(struct notifier_block *nb,
+                                      unsigned long cmd, void *v)
+ {
+       struct omap_dm_timer *timer;
+       timer = container_of(nb, struct omap_dm_timer, nb);
+       switch (cmd) {
+       case CPU_CLUSTER_PM_ENTER:
+               if ((timer->capability & OMAP_TIMER_ALWON) ||
+                   !atomic_read(&timer->enabled))
+                       break;
+               omap_timer_save_context(timer);
+               break;
+       case CPU_CLUSTER_PM_ENTER_FAILED:
+       case CPU_CLUSTER_PM_EXIT:
+               if ((timer->capability & OMAP_TIMER_ALWON) ||
+                   !atomic_read(&timer->enabled))
+                       break;
+               omap_timer_restore_context(timer);
+               break;
+       }
+       return NOTIFY_OK;
+ }
  static int omap_dm_timer_reset(struct omap_dm_timer *timer)
  {
        u32 l, timeout = 100000;
        return 0;
  }
  
 -static int omap_dm_timer_of_set_source(struct omap_dm_timer *timer)
 -{
 -      int ret;
 -      struct clk *parent;
 -
 -      /*
 -       * FIXME: OMAP1 devices do not use the clock framework for dmtimers so
 -       * do not call clk_get() for these devices.
 -       */
 -      if (!timer->fclk)
 -              return -ENODEV;
 -
 -      parent = clk_get(&timer->pdev->dev, NULL);
 -      if (IS_ERR(parent))
 -              return -ENODEV;
 -
 -      /* Bail out if both clocks point to fck */
 -      if (clk_is_match(parent, timer->fclk))
 -              return 0;
 -
 -      ret = clk_set_parent(timer->fclk, parent);
 -      if (ret < 0)
 -              pr_err("%s: failed to set parent\n", __func__);
 -
 -      clk_put(parent);
 -
 -      return ret;
 -}
 -
  static int omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
  {
        int ret;
  
  static void omap_dm_timer_enable(struct omap_dm_timer *timer)
  {
-       int c;
        pm_runtime_get_sync(&timer->pdev->dev);
-       if (!(timer->capability & OMAP_TIMER_ALWON)) {
-               if (timer->get_context_loss_count) {
-                       c = timer->get_context_loss_count(&timer->pdev->dev);
-                       if (c != timer->ctx_loss_count) {
-                               omap_timer_restore_context(timer);
-                               timer->ctx_loss_count = c;
-                       }
-               } else {
-                       omap_timer_restore_context(timer);
-               }
-       }
  }
  
  static void omap_dm_timer_disable(struct omap_dm_timer *timer)
@@@ -247,7 -287,9 +258,7 @@@ static int omap_dm_timer_prepare(struc
        __omap_dm_timer_enable_posted(timer);
        omap_dm_timer_disable(timer);
  
 -      rc = omap_dm_timer_of_set_source(timer);
 -      if (rc == -ENODEV)
 -              return omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
 +      rc = omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
  
        return rc;
  }
@@@ -477,7 -519,7 +488,7 @@@ __u32 omap_dm_timer_modify_idlect_mask(
  
  int omap_dm_timer_trigger(struct omap_dm_timer *timer)
  {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return -EINVAL;
        }
@@@ -501,8 -543,6 +512,6 @@@ static int omap_dm_timer_start(struct o
                omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        }
  
-       /* Save the context */
-       timer->context.tclr = l;
        return 0;
  }
  
@@@ -518,37 -558,19 +527,19 @@@ static int omap_dm_timer_stop(struct om
  
        __omap_dm_timer_stop(timer, timer->posted, rate);
  
-       /*
-        * Since the register values are computed and written within
-        * __omap_dm_timer_stop, we need to use read to retrieve the
-        * context.
-        */
-       timer->context.tclr =
-                       omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        omap_dm_timer_disable(timer);
        return 0;
  }
  
- static int omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload,
+ static int omap_dm_timer_set_load(struct omap_dm_timer *timer,
                                  unsigned int load)
  {
-       u32 l;
        if (unlikely(!timer))
                return -EINVAL;
  
        omap_dm_timer_enable(timer);
-       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
-       if (autoreload)
-               l |= OMAP_TIMER_CTRL_AR;
-       else
-               l &= ~OMAP_TIMER_CTRL_AR;
-       omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
  
-       /* Save the context */
-       timer->context.tclr = l;
-       timer->context.tldr = load;
        omap_dm_timer_disable(timer);
        return 0;
  }
@@@ -570,15 -592,12 +561,12 @@@ static int omap_dm_timer_set_match(stru
        omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  
-       /* Save the context */
-       timer->context.tclr = l;
-       timer->context.tmar = match;
        omap_dm_timer_disable(timer);
        return 0;
  }
  
  static int omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on,
-                                int toggle, int trigger)
+                                int toggle, int trigger, int autoreload)
  {
        u32 l;
  
        omap_dm_timer_enable(timer);
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
        l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM |
-              OMAP_TIMER_CTRL_PT | (0x03 << 10));
+              OMAP_TIMER_CTRL_PT | (0x03 << 10) | OMAP_TIMER_CTRL_AR);
        if (def_on)
                l |= OMAP_TIMER_CTRL_SCPWM;
        if (toggle)
                l |= OMAP_TIMER_CTRL_PT;
        l |= trigger << 10;
+       if (autoreload)
+               l |= OMAP_TIMER_CTRL_AR;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  
-       /* Save the context */
-       timer->context.tclr = l;
        omap_dm_timer_disable(timer);
        return 0;
  }
  
+ static int omap_dm_timer_get_pwm_status(struct omap_dm_timer *timer)
+ {
+       u32 l;
+       if (unlikely(!timer))
+               return -EINVAL;
+       omap_dm_timer_enable(timer);
+       l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+       omap_dm_timer_disable(timer);
+       return l;
+ }
  static int omap_dm_timer_set_prescaler(struct omap_dm_timer *timer,
                                        int prescaler)
  {
        }
        omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
  
-       /* Save the context */
-       timer->context.tclr = l;
        omap_dm_timer_disable(timer);
        return 0;
  }
@@@ -634,9 -665,6 +634,6 @@@ static int omap_dm_timer_set_int_enable
        omap_dm_timer_enable(timer);
        __omap_dm_timer_int_enable(timer, value);
  
-       /* Save the context */
-       timer->context.tier = value;
-       timer->context.twer = value;
        omap_dm_timer_disable(timer);
        return 0;
  }
@@@ -664,9 -692,6 +661,6 @@@ static int omap_dm_timer_set_int_disabl
        l = omap_dm_timer_read_reg(timer, OMAP_TIMER_WAKEUP_EN_REG) & ~mask;
        omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, l);
  
-       /* Save the context */
-       timer->context.tier &= ~mask;
-       timer->context.twer &= ~mask;
        omap_dm_timer_disable(timer);
        return 0;
  }
@@@ -675,7 -700,7 +669,7 @@@ static unsigned int omap_dm_timer_read_
  {
        unsigned int l;
  
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return 0;
        }
  
  static int omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
  {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev)))
+       if (unlikely(!timer || !atomic_read(&timer->enabled)))
                return -EINVAL;
  
        __omap_dm_timer_write_status(timer, value);
  
  static unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
  {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not iavailable or enabled.\n", __func__);
                return 0;
        }
  
  static int omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
  {
-       if (unlikely(!timer || pm_runtime_suspended(&timer->pdev->dev))) {
+       if (unlikely(!timer || !atomic_read(&timer->enabled))) {
                pr_err("%s: timer not available or enabled.\n", __func__);
                return -EINVAL;
        }
@@@ -735,6 -760,37 +729,37 @@@ int omap_dm_timers_active(void
        return 0;
  }
  
+ static int __maybe_unused omap_dm_timer_runtime_suspend(struct device *dev)
+ {
+       struct omap_dm_timer *timer = dev_get_drvdata(dev);
+       atomic_set(&timer->enabled, 0);
+       if (timer->capability & OMAP_TIMER_ALWON || !timer->func_base)
+               return 0;
+       omap_timer_save_context(timer);
+       return 0;
+ }
+ static int __maybe_unused omap_dm_timer_runtime_resume(struct device *dev)
+ {
+       struct omap_dm_timer *timer = dev_get_drvdata(dev);
+       if (!(timer->capability & OMAP_TIMER_ALWON) && timer->func_base)
+               omap_timer_restore_context(timer);
+       atomic_set(&timer->enabled, 1);
+       return 0;
+ }
+ static const struct dev_pm_ops omap_dm_timer_pm_ops = {
+       SET_RUNTIME_PM_OPS(omap_dm_timer_runtime_suspend,
+                          omap_dm_timer_runtime_resume, NULL)
+ };
  static const struct of_device_id omap_timer_match[];
  
  /**
@@@ -776,6 -832,8 +801,8 @@@ static int omap_dm_timer_probe(struct p
        if (IS_ERR(timer->io_base))
                return PTR_ERR(timer->io_base);
  
+       platform_set_drvdata(pdev, timer);
        if (dev->of_node) {
                if (of_find_property(dev->of_node, "ti,timer-alwon", NULL))
                        timer->capability |= OMAP_TIMER_ALWON;
                timer->id = pdev->id;
                timer->capability = pdata->timer_capability;
                timer->reserved = omap_dm_timer_reserved_systimer(timer->id);
-               timer->get_context_loss_count = pdata->get_context_loss_count;
+       }
+       if (!(timer->capability & OMAP_TIMER_ALWON)) {
+               timer->nb.notifier_call = omap_timer_context_notifier;
+               cpu_pm_register_notifier(&timer->nb);
        }
  
        if (pdata)
@@@ -843,6 -905,8 +874,8 @@@ static int omap_dm_timer_remove(struct 
        list_for_each_entry(timer, &omap_timer_list, node)
                if (!strcmp(dev_name(&timer->pdev->dev),
                            dev_name(&pdev->dev))) {
+                       if (!(timer->capability & OMAP_TIMER_ALWON))
+                               cpu_pm_unregister_notifier(&timer->nb);
                        list_del(&timer->node);
                        ret = 0;
                        break;
@@@ -871,6 -935,7 +904,7 @@@ static const struct omap_dm_timer_ops d
        .set_load = omap_dm_timer_set_load,
        .set_match = omap_dm_timer_set_match,
        .set_pwm = omap_dm_timer_set_pwm,
+       .get_pwm_status = omap_dm_timer_get_pwm_status,
        .set_prescaler = omap_dm_timer_set_prescaler,
        .read_counter = omap_dm_timer_read_counter,
        .write_counter = omap_dm_timer_write_counter,
@@@ -921,6 -986,7 +955,7 @@@ static struct platform_driver omap_dm_t
        .driver = {
                .name   = "omap_timer",
                .of_match_table = of_match_ptr(omap_timer_match),
+               .pm = &omap_dm_timer_pm_ops,
        },
  };