summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/regulator/ab8500.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 354962d8f6b..96bf7a50a38 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -34,6 +34,8 @@
* @update_bank: bank to control on/off
* @update_reg: register to control on/off
* @update_mask: mask to enable/disable regulator
+ * @update_val: bits holding the regulator current mode
+ * @update_val_idle: bits to enable the regulator in idle (low power) mode
* @update_val_enable: bits to enable the regulator in normal (high power) mode
* @voltage_bank: bank to control regulator voltage
* @voltage_reg: register to control regulator voltage
@@ -53,6 +55,8 @@ struct ab8500_regulator_info {
u8 update_bank;
u8 update_reg;
u8 update_mask;
+ u8 update_val;
+ u8 update_val_idle;
u8 update_val_enable;
u8 voltage_bank;
u8 voltage_reg;
@@ -154,6 +158,63 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev)
return ret;
}
+static int ab8500_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ /*
+ * update_val_enable is protected by mutex
+ * into regulator/core.c layout
+ */
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ info->update_val = info->update_val_enable;
+ break;
+ case REGULATOR_MODE_IDLE:
+ info->update_val = info->update_val_idle;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ab8500_regulator_enable(rdev);
+}
+
+static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+ u8 regval;
+
+ if (info == NULL) {
+ dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
+ return -EINVAL;
+ }
+
+ ret = abx500_get_register_interruptible(info->dev,
+ info->update_bank, info->update_reg, &regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't read 0x%x register\n", info->update_reg);
+ return ret;
+ }
+
+ regval &=info->update_mask;
+ if (regval == info->update_val_enable)
+ ret = REGULATOR_MODE_NORMAL;
+ else if (regval == info->update_val_idle)
+ ret = REGULATOR_MODE_IDLE;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
static int ab8500_regulator_is_enabled(struct regulator_dev *rdev)
{
int ret;
@@ -322,6 +383,8 @@ static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
static struct regulator_ops ab8500_regulator_ops = {
.enable = ab8500_regulator_enable,
.disable = ab8500_regulator_disable,
+ .set_mode = ab8500_regulator_set_mode,
+ .get_mode = ab8500_regulator_get_mode,
.is_enabled = ab8500_regulator_is_enabled,
.get_voltage = ab8500_regulator_get_voltage,
.set_voltage = ab8500_regulator_set_voltage,
@@ -456,6 +519,8 @@ static struct ab8500_regulator_info
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
.update_val_enable = 0x01,
.voltage_bank = 0x04,
.voltage_reg = 0x1f,
@@ -477,6 +542,8 @@ static struct ab8500_regulator_info
.update_bank = 0x04,
.update_reg = 0x09,
.update_mask = 0x0c,
+ .update_val = 0x04,
+ .update_val_idle = 0x0c,
.update_val_enable = 0x04,
.voltage_bank = 0x04,
.voltage_reg = 0x20,
@@ -498,6 +565,8 @@ static struct ab8500_regulator_info
.update_bank = 0x04,
.update_reg = 0x0a,
.update_mask = 0x03,
+ .update_val = 0x01,
+ .update_val_idle = 0x03,
.update_val_enable = 0x01,
.voltage_bank = 0x04,
.voltage_reg = 0x21,
@@ -519,6 +588,8 @@ static struct ab8500_regulator_info
.update_bank = 0x03,
.update_reg = 0x80,
.update_mask = 0x44,
+ .update_val = 0x04,
+ .update_val_idle = 0x44,
.update_val_enable = 0x04,
.voltage_bank = 0x03,
.voltage_reg = 0x80,