]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/commitdiff
regulator: introduce regulator chain locking scheme
authorGrygorii Strashko <grygorii.strashko@ti.com>
Mon, 8 Apr 2013 15:55:04 +0000 (18:55 +0300)
committerJ Keerthy <j-keerthy@ti.com>
Tue, 28 May 2013 05:39:54 +0000 (11:09 +0530)
In some cases the regulators may be organized in a chain like:
  ->regA->regB->regC
where regA is supplier for regB and regB is supplier for regC.

Currently it would be possible to reconfigure regA and regC at same time
form different contexts, because each regulator has it own mutex.
But in some cases, the only the whole chain is allowed be reconfigured
because of dependencies between regulators - to change regB
configuration the regA need to be updated first.

Hence, introduce regulator chain locking scheme to lock whole Regulator
chain in case if any part of it has been accessed from outside. To
achieve this goal the root Regulator (which has no supply defined, like
regA) in chain is used to protect the whole chain.

In addition, such locking scheme allows to have access to the supplier
regulator API from inside child's (consumer) regulator API.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
drivers/regulator/core.c
include/linux/regulator/driver.h

index 0c00d111171a46548f36148b49b9003b0821628f..d9c089ca1338a90620f75fd4dcdbe844c789fe5d 100644 (file)
@@ -110,18 +110,48 @@ static const char *rdev_get_name(struct regulator_dev *rdev)
                return "";
 }
 
-
-static inline void regulator_lock(struct regulator_dev *rdev)
+static void regulator_lock(struct regulator_dev *rdev)
 {
        struct regulator_dev *locking_rdev = rdev;
 
-       mutex_lock(&locking_rdev->mutex);
+       while (locking_rdev->supply)
+               locking_rdev = locking_rdev->supply->rdev;
+
+       if (!mutex_trylock(&locking_rdev->mutex)) {
+               if (locking_rdev->lock_owner == current) {
+                       locking_rdev->lock_count++;
+                       dev_dbg(&locking_rdev->dev,
+                               "Is locked. locking %s (ref=%u)\n",
+                               rdev_get_name(rdev),
+                               locking_rdev->lock_count);
+                       return;
+               }
+               mutex_lock(&locking_rdev->mutex);
+       }
+
+       WARN_ON_ONCE(locking_rdev->lock_owner != NULL);
+       WARN_ON_ONCE(locking_rdev->lock_count != 0);
+
+       locking_rdev->lock_count = 1;
+       locking_rdev->lock_owner = current;
+       dev_dbg(&locking_rdev->dev, "Is locked. locking %s\n",
+               rdev_get_name(rdev));
 }
 
-static inline void regulator_unlock(struct regulator_dev *rdev)
+static void regulator_unlock(struct regulator_dev *rdev)
 {
        struct regulator_dev *locking_rdev = rdev;
 
+       while (locking_rdev->supply)
+               locking_rdev = locking_rdev->supply->rdev;
+
+       dev_dbg(&locking_rdev->dev, "Is unlocked. unlocking %s (ref=%u)\n",
+               rdev_get_name(rdev), locking_rdev->lock_count);
+
+       if (--locking_rdev->lock_count)
+               return;
+
+       locking_rdev->lock_owner = NULL;
        mutex_unlock(&locking_rdev->mutex);
 }
 
index d10bb0f39c5e72fd6bb7747e47761d062f75c981..eea5af05a948b0c2cafa8bc89a0f2c180ad9d4a8 100644 (file)
@@ -281,6 +281,8 @@ struct regulator_dev {
 
        struct blocking_notifier_head notifier;
        struct mutex mutex; /* consumer lock */
+       struct task_struct *lock_owner;
+       int lock_count;
        struct module *owner;
        struct device dev;
        struct regulation_constraints *constraints;