Merge commit 'f17a0dd1c2e0' into clk-next
authorMichael Turquette <mturquette@baylibre.com>
Fri, 17 Jun 2016 05:07:08 +0000 (22:07 -0700)
committerMichael Turquette <mturquette@baylibre.com>
Fri, 17 Jun 2016 05:07:08 +0000 (22:07 -0700)
1  2 
drivers/clk/clk.c

diff --combined drivers/clk/clk.c
@@@ -574,9 -574,6 +574,9 @@@ static void clk_core_unprepare(struct c
        if (WARN_ON(core->prepare_count == 0))
                return;
  
 +      if (WARN_ON(core->prepare_count == 1 && core->flags & CLK_IS_CRITICAL))
 +              return;
 +
        if (--core->prepare_count > 0)
                return;
  
@@@ -682,18 -679,15 +682,18 @@@ static void clk_core_disable(struct clk
        if (WARN_ON(core->enable_count == 0))
                return;
  
 +      if (WARN_ON(core->enable_count == 1 && core->flags & CLK_IS_CRITICAL))
 +              return;
 +
        if (--core->enable_count > 0)
                return;
  
-       trace_clk_disable(core);
+       trace_clk_disable_rcuidle(core);
  
        if (core->ops->disable)
                core->ops->disable(core->hw);
  
-       trace_clk_disable_complete(core);
+       trace_clk_disable_complete_rcuidle(core);
  
        clk_core_disable(core->parent);
  }
@@@ -741,12 -735,12 +741,12 @@@ static int clk_core_enable(struct clk_c
                if (ret)
                        return ret;
  
-               trace_clk_enable(core);
+               trace_clk_enable_rcuidle(core);
  
                if (core->ops->enable)
                        ret = core->ops->enable(core->hw);
  
-               trace_clk_enable_complete(core);
+               trace_clk_enable_complete_rcuidle(core);
  
                if (ret) {
                        clk_core_disable(core->parent);
@@@ -2403,16 -2397,6 +2403,16 @@@ static int __clk_core_init(struct clk_c
        if (core->ops->init)
                core->ops->init(core->hw);
  
 +      if (core->flags & CLK_IS_CRITICAL) {
 +              unsigned long flags;
 +
 +              clk_core_prepare(core);
 +
 +              flags = clk_enable_lock();
 +              clk_core_enable(core);
 +              clk_enable_unlock(flags);
 +      }
 +
        kref_init(&core->ref);
  out:
        clk_prepare_unlock();
@@@ -2552,22 -2536,6 +2552,22 @@@ fail_out
  }
  EXPORT_SYMBOL_GPL(clk_register);
  
 +/**
 + * clk_hw_register - register a clk_hw and return an error code
 + * @dev: device that is registering this clock
 + * @hw: link to hardware-specific clock data
 + *
 + * clk_hw_register is the primary interface for populating the clock tree with
 + * new clock nodes. It returns an integer equal to zero indicating success or
 + * less than zero indicating failure. Drivers must test for an error code after
 + * calling clk_hw_register().
 + */
 +int clk_hw_register(struct device *dev, struct clk_hw *hw)
 +{
 +      return PTR_ERR_OR_ZERO(clk_register(dev, hw));
 +}
 +EXPORT_SYMBOL_GPL(clk_hw_register);
 +
  /* Free memory allocated for a clock. */
  static void __clk_release(struct kref *ref)
  {
@@@ -2669,26 -2637,11 +2669,26 @@@ unlock
  }
  EXPORT_SYMBOL_GPL(clk_unregister);
  
 +/**
 + * clk_hw_unregister - unregister a currently registered clk_hw
 + * @hw: hardware-specific clock data to unregister
 + */
 +void clk_hw_unregister(struct clk_hw *hw)
 +{
 +      clk_unregister(hw->clk);
 +}
 +EXPORT_SYMBOL_GPL(clk_hw_unregister);
 +
  static void devm_clk_release(struct device *dev, void *res)
  {
        clk_unregister(*(struct clk **)res);
  }
  
 +static void devm_clk_hw_release(struct device *dev, void *res)
 +{
 +      clk_hw_unregister(*(struct clk_hw **)res);
 +}
 +
  /**
   * devm_clk_register - resource managed clk_register()
   * @dev: device that is registering this clock
@@@ -2719,36 -2672,6 +2719,36 @@@ struct clk *devm_clk_register(struct de
  }
  EXPORT_SYMBOL_GPL(devm_clk_register);
  
 +/**
 + * devm_clk_hw_register - resource managed clk_hw_register()
 + * @dev: device that is registering this clock
 + * @hw: link to hardware-specific clock data
 + *
 + * Managed clk_hw_register(). Clocks registered by this function are
 + * automatically clk_hw_unregister()ed on driver detach. See clk_hw_register()
 + * for more information.
 + */
 +int devm_clk_hw_register(struct device *dev, struct clk_hw *hw)
 +{
 +      struct clk_hw **hwp;
 +      int ret;
 +
 +      hwp = devres_alloc(devm_clk_hw_release, sizeof(*hwp), GFP_KERNEL);
 +      if (!hwp)
 +              return -ENOMEM;
 +
 +      ret = clk_hw_register(dev, hw);
 +      if (!ret) {
 +              *hwp = hw;
 +              devres_add(dev, hwp);
 +      } else {
 +              devres_free(hwp);
 +      }
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(devm_clk_hw_register);
 +
  static int devm_clk_match(struct device *dev, void *res, void *data)
  {
        struct clk *c = res;
        return c == data;
  }
  
 +static int devm_clk_hw_match(struct device *dev, void *res, void *data)
 +{
 +      struct clk_hw *hw = res;
 +
 +      if (WARN_ON(!hw))
 +              return 0;
 +      return hw == data;
 +}
 +
  /**
   * devm_clk_unregister - resource managed clk_unregister()
   * @clk: clock to unregister
@@@ -2780,22 -2694,6 +2780,22 @@@ void devm_clk_unregister(struct device 
  }
  EXPORT_SYMBOL_GPL(devm_clk_unregister);
  
 +/**
 + * devm_clk_hw_unregister - resource managed clk_hw_unregister()
 + * @dev: device that is unregistering the hardware-specific clock data
 + * @hw: link to hardware-specific clock data
 + *
 + * Unregister a clk_hw registered with devm_clk_hw_register(). Normally
 + * this function will not need to be called and the resource management
 + * code will ensure that the resource is freed.
 + */
 +void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw)
 +{
 +      WARN_ON(devres_release(dev, devm_clk_hw_release, devm_clk_hw_match,
 +                              hw));
 +}
 +EXPORT_SYMBOL_GPL(devm_clk_hw_unregister);
 +
  /*
   * clkdev helpers
   */
@@@ -2957,7 -2855,6 +2957,7 @@@ struct of_clk_provider 
  
        struct device_node *node;
        struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
 +      struct clk_hw *(*get_hw)(struct of_phandle_args *clkspec, void *data);
        void *data;
  };
  
@@@ -2974,12 -2871,6 +2974,12 @@@ struct clk *of_clk_src_simple_get(struc
  }
  EXPORT_SYMBOL_GPL(of_clk_src_simple_get);
  
 +struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data)
 +{
 +      return data;
 +}
 +EXPORT_SYMBOL_GPL(of_clk_hw_simple_get);
 +
  struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
  {
        struct clk_onecell_data *clk_data = data;
  }
  EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
  
 +struct clk_hw *
 +of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data)
 +{
 +      struct clk_hw_onecell_data *hw_data = data;
 +      unsigned int idx = clkspec->args[0];
 +
 +      if (idx >= hw_data->num) {
 +              pr_err("%s: invalid index %u\n", __func__, idx);
 +              return ERR_PTR(-EINVAL);
 +      }
 +
 +      return hw_data->hws[idx];
 +}
 +EXPORT_SYMBOL_GPL(of_clk_hw_onecell_get);
 +
  /**
   * of_clk_add_provider() - Register a clock provider for a node
   * @np: Device node pointer associated with clock provider
@@@ -3044,41 -2920,6 +3044,41 @@@ int of_clk_add_provider(struct device_n
  }
  EXPORT_SYMBOL_GPL(of_clk_add_provider);
  
 +/**
 + * of_clk_add_hw_provider() - Register a clock provider for a node
 + * @np: Device node pointer associated with clock provider
 + * @get: callback for decoding clk_hw
 + * @data: context pointer for @get callback.
 + */
 +int of_clk_add_hw_provider(struct device_node *np,
 +                         struct clk_hw *(*get)(struct of_phandle_args *clkspec,
 +                                               void *data),
 +                         void *data)
 +{
 +      struct of_clk_provider *cp;
 +      int ret;
 +
 +      cp = kzalloc(sizeof(*cp), GFP_KERNEL);
 +      if (!cp)
 +              return -ENOMEM;
 +
 +      cp->node = of_node_get(np);
 +      cp->data = data;
 +      cp->get_hw = get;
 +
 +      mutex_lock(&of_clk_mutex);
 +      list_add(&cp->link, &of_clk_providers);
 +      mutex_unlock(&of_clk_mutex);
 +      pr_debug("Added clk_hw provider from %s\n", np->full_name);
 +
 +      ret = of_clk_set_defaults(np, true);
 +      if (ret < 0)
 +              of_clk_del_provider(np);
 +
 +      return ret;
 +}
 +EXPORT_SYMBOL_GPL(of_clk_add_hw_provider);
 +
  /**
   * of_clk_del_provider() - Remove a previously registered clock provider
   * @np: Device node pointer associated with clock provider
@@@ -3100,32 -2941,11 +3100,32 @@@ void of_clk_del_provider(struct device_
  }
  EXPORT_SYMBOL_GPL(of_clk_del_provider);
  
 +static struct clk_hw *
 +__of_clk_get_hw_from_provider(struct of_clk_provider *provider,
 +                            struct of_phandle_args *clkspec)
 +{
 +      struct clk *clk;
 +      struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
 +
 +      if (provider->get_hw) {
 +              hw = provider->get_hw(clkspec, provider->data);
 +      } else if (provider->get) {
 +              clk = provider->get(clkspec, provider->data);
 +              if (!IS_ERR(clk))
 +                      hw = __clk_get_hw(clk);
 +              else
 +                      hw = ERR_CAST(clk);
 +      }
 +
 +      return hw;
 +}
 +
  struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
                                       const char *dev_id, const char *con_id)
  {
        struct of_clk_provider *provider;
        struct clk *clk = ERR_PTR(-EPROBE_DEFER);
 +      struct clk_hw *hw = ERR_PTR(-EPROBE_DEFER);
  
        if (!clkspec)
                return ERR_PTR(-EINVAL);
        mutex_lock(&of_clk_mutex);
        list_for_each_entry(provider, &of_clk_providers, link) {
                if (provider->node == clkspec->np)
 -                      clk = provider->get(clkspec, provider->data);
 -              if (!IS_ERR(clk)) {
 -                      clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
 -                                             con_id);
 +                      hw = __of_clk_get_hw_from_provider(provider, clkspec);
 +              if (!IS_ERR(hw)) {
 +                      clk = __clk_create_clk(hw, dev_id, con_id);
  
                        if (!IS_ERR(clk) && !__clk_get(clk)) {
                                __clk_free_clk(clk);
@@@ -3305,41 -3126,6 +3305,41 @@@ static int parent_ready(struct device_n
        }
  }
  
 +/**
 + * of_clk_detect_critical() - set CLK_IS_CRITICAL flag from Device Tree
 + * @np: Device node pointer associated with clock provider
 + * @index: clock index
 + * @flags: pointer to clk_core->flags
 + *
 + * Detects if the clock-critical property exists and, if so, sets the
 + * corresponding CLK_IS_CRITICAL flag.
 + *
 + * Do not use this function. It exists only for legacy Device Tree
 + * bindings, such as the one-clock-per-node style that are outdated.
 + * Those bindings typically put all clock data into .dts and the Linux
 + * driver has no clock data, thus making it impossible to set this flag
 + * correctly from the driver. Only those drivers may call
 + * of_clk_detect_critical from their setup functions.
 + *
 + * Return: error code or zero on success
 + */
 +int of_clk_detect_critical(struct device_node *np,
 +                                        int index, unsigned long *flags)
 +{
 +      struct property *prop;
 +      const __be32 *cur;
 +      uint32_t idx;
 +
 +      if (!np || !flags)
 +              return -EINVAL;
 +
 +      of_property_for_each_u32(np, "clock-critical", prop, cur, idx)
 +              if (index == idx)
 +                      *flags |= CLK_IS_CRITICAL;
 +
 +      return 0;
 +}
 +
  /**
   * of_clk_init() - Scan and init clock providers from the DT
   * @matches: array of compatible values and init functions for providers.