clk: keystone: sci-clk: Fix sci_clk_get
[sfrench/cifs-2.6.git] / drivers / clk / keystone / sci-clk.c
index 43b0f2f08df2f7536d2f09e4f37984dde090e474..9cdf9d5050aca80858d3dc9dfcea416d91912b97 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/soc/ti/ti_sci_protocol.h>
+#include <linux/bsearch.h>
 
 #define SCI_CLK_SSC_ENABLE             BIT(0)
 #define SCI_CLK_ALLOW_FREQ_CHANGE      BIT(1)
@@ -44,6 +45,7 @@ struct sci_clk_data {
  * @dev: Device pointer for the clock provider
  * @clk_data: Clock data
  * @clocks: Clocks array for this device
+ * @num_clocks: Total number of clocks for this provider
  */
 struct sci_clk_provider {
        const struct ti_sci_handle *sci;
@@ -51,6 +53,7 @@ struct sci_clk_provider {
        struct device *dev;
        const struct sci_clk_data *clk_data;
        struct clk_hw **clocks;
+       int num_clocks;
 };
 
 /**
@@ -58,7 +61,6 @@ struct sci_clk_provider {
  * @hw:                 Hardware clock cookie for common clock framework
  * @dev_id:     Device index
  * @clk_id:     Clock index
- * @node:       Clocks list link
  * @provider:   Master clock provider
  * @flags:      Flags for the clock
  */
@@ -66,7 +68,6 @@ struct sci_clk {
        struct clk_hw hw;
        u16 dev_id;
        u8 clk_id;
-       struct list_head node;
        struct sci_clk_provider *provider;
        u8 flags;
 };
@@ -367,6 +368,19 @@ err:
        return &sci_clk->hw;
 }
 
+static int _cmp_sci_clk(const void *a, const void *b)
+{
+       const struct sci_clk *ca = a;
+       const struct sci_clk *cb = *(struct sci_clk **)b;
+
+       if (ca->dev_id == cb->dev_id && ca->clk_id == cb->clk_id)
+               return 0;
+       if (ca->dev_id > cb->dev_id ||
+           (ca->dev_id == cb->dev_id && ca->clk_id > cb->clk_id))
+               return 1;
+       return -1;
+}
+
 /**
  * sci_clk_get - Xlate function for getting clock handles
  * @clkspec: device tree clock specifier
@@ -380,29 +394,22 @@ err:
 static struct clk_hw *sci_clk_get(struct of_phandle_args *clkspec, void *data)
 {
        struct sci_clk_provider *provider = data;
-       u16 dev_id;
-       u8 clk_id;
-       const struct sci_clk_data *clks = provider->clk_data;
-       struct clk_hw **clocks = provider->clocks;
+       struct sci_clk **clk;
+       struct sci_clk key;
 
        if (clkspec->args_count != 2)
                return ERR_PTR(-EINVAL);
 
-       dev_id = clkspec->args[0];
-       clk_id = clkspec->args[1];
+       key.dev_id = clkspec->args[0];
+       key.clk_id = clkspec->args[1];
 
-       while (clks->num_clks) {
-               if (clks->dev == dev_id) {
-                       if (clk_id >= clks->num_clks)
-                               return ERR_PTR(-EINVAL);
-
-                       return clocks[clk_id];
-               }
+       clk = bsearch(&key, provider->clocks, provider->num_clocks,
+                     sizeof(clk), _cmp_sci_clk);
 
-               clks++;
-       }
+       if (!clk)
+               return ERR_PTR(-ENODEV);
 
-       return ERR_PTR(-ENODEV);
+       return &(*clk)->hw;
 }
 
 static int ti_sci_init_clocks(struct sci_clk_provider *p)
@@ -410,18 +417,29 @@ static int ti_sci_init_clocks(struct sci_clk_provider *p)
        const struct sci_clk_data *data = p->clk_data;
        struct clk_hw *hw;
        int i;
+       int num_clks = 0;
 
        while (data->num_clks) {
-               p->clocks = devm_kcalloc(p->dev, data->num_clks,
-                                        sizeof(struct sci_clk),
-                                        GFP_KERNEL);
-               if (!p->clocks)
-                       return -ENOMEM;
+               num_clks += data->num_clks;
+               data++;
+       }
 
+       p->num_clocks = num_clks;
+
+       p->clocks = devm_kcalloc(p->dev, num_clks, sizeof(struct sci_clk),
+                                GFP_KERNEL);
+       if (!p->clocks)
+               return -ENOMEM;
+
+       num_clks = 0;
+
+       data = p->clk_data;
+
+       while (data->num_clks) {
                for (i = 0; i < data->num_clks; i++) {
                        hw = _sci_clk_build(p, data->dev, i);
                        if (!IS_ERR(hw)) {
-                               p->clocks[i] = hw;
+                               p->clocks[num_clks++] = hw;
                                continue;
                        }