* @voltage_bank: bank to control regulator voltage
* @voltage_reg: register to control regulator voltage
* @voltage_mask: mask to control regulator voltage
- * @voltage_shift: shift to control regulator voltage
*/
struct ab8500_regulator_info {
struct device *dev;
u8 voltage_bank;
u8 voltage_reg;
u8 voltage_mask;
- u8 voltage_shift;
struct {
u8 voltage_limit;
u8 voltage_bank;
u8 voltage_reg;
u8 voltage_mask;
- u8 voltage_shift;
} expand_register;
};
unsigned int mode)
{
int ret = 0;
- u8 bank;
- u8 reg;
- u8 mask;
- u8 val;
- bool dmr = false; /* Dedicated mode register */
+ u8 bank, reg, mask, val;
+ bool lp_mode_req = false;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
if (info == NULL) {
return -EINVAL;
}
- if (info->shared_mode) {
- /*
- * Special case where mode is shared between two regulators.
- */
- struct ab8500_shared_mode *sm = info->shared_mode;
- mutex_lock(&shared_mode_mutex);
-
- if (mode == REGULATOR_MODE_IDLE) {
- sm->lp_mode_req = true; /* Low power mode requested */
- if (!((sm->shared_regulator)->
- shared_mode->lp_mode_req)) {
- mutex_unlock(&shared_mode_mutex);
- return 0; /* Other regulator prevent LP mode */
- }
- } else {
- sm->lp_mode_req = false;
- }
- }
-
if (info->mode_mask) {
- /* Dedicated register for handling mode */
-
- dmr = true;
-
- switch (mode) {
- case REGULATOR_MODE_NORMAL:
- val = info->mode_val_normal;
- break;
- case REGULATOR_MODE_IDLE:
- val = info->mode_val_idle;
- break;
- default:
- ret = -EINVAL;
- goto out_unlock;
- }
-
bank = info->mode_bank;
reg = info->mode_reg;
mask = info->mode_mask;
} else {
- /* Mode register same as enable register */
+ bank = info->update_bank;
+ reg = info->update_reg;
+ mask = info->update_mask;
+ }
+
+ if (info->shared_mode)
+ mutex_lock(&shared_mode_mutex);
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ if (info->shared_mode)
+ lp_mode_req = false;
- switch (mode) {
- case REGULATOR_MODE_NORMAL:
+ if (info->mode_mask)
+ val = info->mode_val_normal;
+ else
val = info->update_val_normal;
- break;
- case REGULATOR_MODE_IDLE:
- val = info->update_val_idle;
- break;
- default:
- ret = -EINVAL;
- goto out_unlock;
+ break;
+ case REGULATOR_MODE_IDLE:
+ if (info->shared_mode) {
+ struct ab8500_regulator_info *shared_regulator;
+
+ shared_regulator = info->shared_mode->shared_regulator;
+ if (!shared_regulator->shared_mode->lp_mode_req) {
+ /* Other regulator prevent LP mode */
+ info->shared_mode->lp_mode_req = true;
+ goto out_unlock;
+ }
+
+ lp_mode_req = true;
}
- bank = info->update_bank;
- reg = info->update_reg;
- mask = info->update_mask;
+ if (info->mode_mask)
+ val = info->mode_val_idle;
+ else
+ val = info->update_val_idle;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out_unlock;
}
- if (dmr || ab8500_regulator_is_enabled(rdev)) {
+ if (info->mode_mask || ab8500_regulator_is_enabled(rdev)) {
ret = abx500_mask_and_set_register_interruptible(info->dev,
bank, reg, mask, val);
if (ret < 0) {
mask, val);
}
- if (!dmr)
+ if (!info->mode_mask)
info->update_val = val;
+ if (info->shared_mode)
+ info->shared_mode->lp_mode_req = lp_mode_req;
+
out_unlock:
if (info->shared_mode)
mutex_unlock(&shared_mode_mutex);
static int ab8500_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
- int ret, val;
+ int ret, voltage_shift;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
u8 regval;
return -EINVAL;
}
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
ret = abx500_get_register_interruptible(info->dev,
info->voltage_bank, info->voltage_reg, ®val);
if (ret < 0) {
"0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
info->desc.name, info->voltage_bank,
info->voltage_reg, info->voltage_mask,
- info->voltage_shift, regval);
+ voltage_shift, regval);
- val = regval & info->voltage_mask;
- return val >> info->voltage_shift;
+ return (regval & info->voltage_mask) >> voltage_shift;
}
static int ab8540_aux3_regulator_get_voltage_sel(struct regulator_dev *rdev)
{
- int ret;
+ int ret, voltage_shift;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
u8 regval, regval_expand;
info->desc.name, info->voltage_bank, info->voltage_reg,
info->voltage_mask, regval);
- return (regval & info->voltage_mask) >> info->voltage_shift;
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
+ return (regval & info->voltage_mask) >> voltage_shift;
}
static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
unsigned selector)
{
- int ret;
+ int ret, voltage_shift;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
u8 regval;
return -EINVAL;
}
+ voltage_shift = ffs(info->voltage_mask) - 1;
+
/* set the registers for the request */
- regval = (u8)selector << info->voltage_shift;
+ regval = (u8)selector << voltage_shift;
ret = abx500_mask_and_set_register_interruptible(info->dev,
info->voltage_bank, info->voltage_reg,
info->voltage_mask, regval);
{
int ret;
struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
- u8 regval;
+ u8 regval, regval_expand;
if (info == NULL) {
dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
return -EINVAL;
}
- if (selector >= info->expand_register.voltage_limit) {
- /* Vaux3 bit4 has different layout */
- regval = (u8)selector << info->expand_register.voltage_shift;
+ if (selector < info->expand_register.voltage_limit) {
+ int voltage_shift = ffs(info->voltage_mask) - 1;
+
+ regval = (u8)selector << voltage_shift;
ret = abx500_mask_and_set_register_interruptible(info->dev,
- info->expand_register.voltage_bank,
- info->expand_register.voltage_reg,
- info->expand_register.voltage_mask,
- regval);
+ info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+ if (ret < 0) {
+ dev_err(rdev_get_dev(rdev),
+ "couldn't set voltage reg for regulator\n");
+ return ret;
+ }
+
+ dev_vdbg(rdev_get_dev(rdev),
+ "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->voltage_bank, info->voltage_reg,
+ info->voltage_mask, regval);
+
+ regval_expand = 0;
} else {
- /* set the registers for the request */
- regval = (u8)selector << info->voltage_shift;
- ret = abx500_mask_and_set_register_interruptible(info->dev,
- info->voltage_bank, info->voltage_reg,
- info->voltage_mask, regval);
+ regval_expand = info->expand_register.voltage_mask;
}
- if (ret < 0)
+
+ ret = abx500_mask_and_set_register_interruptible(info->dev,
+ info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg,
+ info->expand_register.voltage_mask,
+ regval_expand);
+ if (ret < 0) {
dev_err(rdev_get_dev(rdev),
- "couldn't set voltage reg for regulator\n");
+ "couldn't set expand voltage reg for regulator\n");
+ return ret;
+ }
dev_vdbg(rdev_get_dev(rdev),
- "%s-set_voltage (bank, reg, mask, value): 0x%x, 0x%x, 0x%x,"
- " 0x%x\n",
- info->desc.name, info->voltage_bank, info->voltage_reg,
- info->voltage_mask, regval);
+ "%s-set_voltage expand (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n",
+ info->desc.name, info->expand_register.voltage_bank,
+ info->expand_register.voltage_reg,
+ info->expand_register.voltage_mask, regval_expand);
- return ret;
+ return 0;
}
static struct regulator_ops ab8500_regulator_volt_mode_ops = {
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltage_shift = 3,
},
/*
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltage_shift = 3,
},
/*
.voltage_bank = 0x01,
.voltage_reg = 0x57,
.voltage_mask = 0x70,
- .voltage_shift = 4,
},
[AB8505_LDO_ANAMIC1] = {
.desc = {
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltage_shift = 3,
},
/*
.voltage_bank = 0x04,
.voltage_reg = 0x01,
.voltage_mask = 0x10,
- .voltage_shift = 1,
}
},
[AB8540_LDO_AUX4] = {
.voltage_bank = 0x03,
.voltage_reg = 0x80,
.voltage_mask = 0x38,
- .voltage_shift = 3,
},
/*
.voltage_bank = 0x03,
.voltage_reg = 0x83,
.voltage_mask = 0xc0,
- .voltage_shift = 6,
},
/*