reset: core: add support to non-DT reset controller
Laxman Dewangan [Mon, 15 Jun 2015 13:59:35 +0000 (18:59 +0530)]
Add support to register and provide the reset control
functionality for non-DT reset controller.

Non DT reset controller will provide callback for consumer
mapping with device and reset names so that client can
connect to the desired reset controller.

Change-Id: I82d759e7b0a7c228f51e8171c2303e3b6a9b9ac8
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/759024

drivers/reset/core.c
include/linux/reset-controller.h

index baeaf82..589cfd7 100644 (file)
@@ -155,6 +155,9 @@ struct reset_control *of_reset_control_get(struct device_node *node,
        mutex_lock(&reset_controller_list_mutex);
        rcdev = NULL;
        list_for_each_entry(r, &reset_controller_list, list) {
+               if (!r->of_node)
+                       continue;
+
                if (args.np == r->of_node) {
                        rcdev = r;
                        break;
@@ -190,6 +193,55 @@ struct reset_control *of_reset_control_get(struct device_node *node,
 EXPORT_SYMBOL_GPL(of_reset_control_get);
 
 /**
+ * non_reset_control_get - Lookup and obtain a reference to a reset controller.
+ * @node: device to be reset by the controller
+ * @id: reset line name
+ *
+ * Returns a struct reset_control or IS_ERR() condition containing errno.
+ *
+ * Use of id names is optional.
+ */
+static struct reset_control *non_of_reset_control_get(struct device *dev,
+                                          const char *id)
+{
+       struct reset_control *rstc = ERR_PTR(-EPROBE_DEFER);
+       struct reset_controller_dev *r, *rcdev;
+       int rstc_id = -EINVAL;
+
+       mutex_lock(&reset_controller_list_mutex);
+       rcdev = NULL;
+       list_for_each_entry(r, &reset_controller_list, list) {
+               if (!r->consumer_map)
+                       continue;
+
+               rstc_id = r->consumer_map(r, dev, id);
+               if (rstc_id >= 0) {
+                       rcdev = r;
+                       break;
+               }
+       }
+
+       if (!rcdev) {
+               mutex_unlock(&reset_controller_list_mutex);
+               return ERR_PTR(-EPROBE_DEFER);
+       }
+
+       try_module_get(rcdev->owner);
+       mutex_unlock(&reset_controller_list_mutex);
+
+       rstc = kzalloc(sizeof(*rstc), GFP_KERNEL);
+       if (!rstc) {
+               module_put(rcdev->owner);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       rstc->rcdev = rcdev;
+       rstc->id = rstc_id;
+
+       return rstc;
+}
+
+/**
  * reset_control_get - Lookup and obtain a reference to a reset controller.
  * @dev: device to be reset by the controller
  * @id: reset line name
@@ -206,9 +258,17 @@ struct reset_control *reset_control_get(struct device *dev, const char *id)
                return ERR_PTR(-EINVAL);
 
        rstc = of_reset_control_get(dev->of_node, id);
+       if (!IS_ERR(rstc)) {
+               rstc->dev = dev;
+               goto done;
+       }
+
+       /* Try with non-of reset control */
+       rstc = non_of_reset_control_get(dev, id);
        if (!IS_ERR(rstc))
                rstc->dev = dev;
 
+done:
        return rstc;
 }
 EXPORT_SYMBOL_GPL(reset_control_get);
index 2f61311..aa024af 100644 (file)
@@ -32,6 +32,8 @@ struct device_node;
  * @of_reset_n_cells: number of cells in reset line specifiers
  * @of_xlate: translation function to translate from specifier as found in the
  *            device tree to id as given to the reset control ops
+ * @consumer_map: Mapping function for non-DT reset driver to map with
+ *           client and connection name.
  * @nr_resets: number of reset controls in this reset controller device
  */
 struct reset_controller_dev {
@@ -42,6 +44,8 @@ struct reset_controller_dev {
        int of_reset_n_cells;
        int (*of_xlate)(struct reset_controller_dev *rcdev,
                        const struct of_phandle_args *reset_spec);
+       int (*consumer_map)(struct reset_controller_dev *rcdev,
+                       struct device *dev, const char *conn);
        unsigned int nr_resets;
 };