regulator: add sysfs for rail enable/disable
Laxman Dewangan [Thu, 26 Apr 2012 18:49:43 +0000 (23:49 +0530)]
Added support for enable/disable rails from user space.

bug 966960

Change-Id: Iae660699c60f537296f90508a78bd40959c46535
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-on: http://git-master/r/99186
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Hunk Lin <hulin@nvidia.com>
Tested-by: Hunk Lin <hulin@nvidia.com>
GVS: Gerrit_Virtual_Submit

drivers/regulator/core.c

index 1b7d641..cbe36b9 100644 (file)
@@ -91,6 +91,8 @@ struct regulator {
 
 static int _regulator_is_enabled(struct regulator_dev *rdev);
 static int _regulator_disable(struct regulator_dev *rdev);
+static int _regulator_enable(struct regulator_dev *rdev);
+static int _regulator_get_enable_time(struct regulator_dev *rdev);
 static int _regulator_get_voltage(struct regulator_dev *rdev);
 static int _regulator_get_current_limit(struct regulator_dev *rdev);
 static unsigned int _regulator_get_mode(struct regulator_dev *rdev);
@@ -358,7 +360,65 @@ static ssize_t regulator_state_show(struct device *dev,
 
        return ret;
 }
-static DEVICE_ATTR(state, 0444, regulator_state_show, NULL);
+
+static ssize_t regulator_state_set(struct device *dev,
+                  struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct regulator_dev *rdev = dev_get_drvdata(dev);
+       int ret;
+       bool enabled;
+
+       if ((*buf == 'E') || (*buf == 'e'))
+               enabled = true;
+       else if ((*buf == 'D') || (*buf == 'd'))
+               enabled = false;
+       else
+               return -EINVAL;
+
+       if ((_regulator_is_enabled(rdev) && enabled) ||
+               (!_regulator_is_enabled(rdev) && !enabled))
+               return count;
+
+       mutex_lock(&rdev->mutex);
+       if (enabled) {
+               int delay = 0;
+               if (!rdev->desc->ops->enable) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+               ret = _regulator_get_enable_time(rdev);
+               if (ret >= 0)
+                       delay = ret;
+               ret = rdev->desc->ops->enable(rdev);
+               if (ret < 0) {
+                       rdev_warn(rdev, "enable() failed: %d\n", ret);
+                       goto end;
+               }
+               if (delay >= 1000) {
+                       mdelay(delay / 1000);
+                       udelay(delay % 1000);
+               } else if (delay) {
+                       udelay(delay);
+               }
+       } else {
+               if (!rdev->desc->ops->disable) {
+                       ret = -EINVAL;
+                       goto end;
+               }
+               ret = rdev->desc->ops->disable(rdev);
+               if (ret < 0) {
+                       rdev_warn(rdev, "disable() failed: %d\n", ret);
+                       goto end;
+               }
+       }
+
+end:
+       mutex_unlock(&rdev->mutex);
+       if (ret < 0)
+               return ret;
+       return count;
+}
+static DEVICE_ATTR(state, 0644, regulator_state_show, regulator_state_set);
 
 static ssize_t regulator_status_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)