diff options
Diffstat (limited to 'drivers/regulator/ab8500.c')
-rw-r--r-- | drivers/regulator/ab8500.c | 512 |
1 files changed, 443 insertions, 69 deletions
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 02f3c2333c8..0480f55b101 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -20,43 +20,54 @@ #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab8500.h> +#include <linux/mfd/ab8500/gpio.h> /* for sysclkreq pins */ /** * struct ab8500_regulator_info - ab8500 regulator information * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device + * @is_enabled: status of regulator (on/off) * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) * @fixed_uV: typical voltage (for fixed voltage supplies) + * @load_lp_uA: maximum load in idle (low power) mode * @update_bank: bank to control on/off * @update_reg: register to control on/off - * @update_mask: mask to enable/disable regulator - * @update_val_enable: bits to enable the regulator in normal (high power) mode + * @update_mask: mask to enable/disable and set mode of regulator + * @update_val: bits holding the regulator current mode + * @update_val_idle: bits to enable the regulator in idle (low power) mode + * @update_val_normal: bits to enable the regulator in normal (high power) mode * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage * @voltages: supported voltage table * @voltages_len: number of supported voltages for the regulator * @delay: startup/set voltage delay in us + * @gpio_pin: ab8500 gpio pin offset number (for sysclkreq regulator only) */ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; struct regulator_dev *regulator; + bool is_enabled; int max_uV; int min_uV; int fixed_uV; + int load_lp_uA; u8 update_bank; u8 update_reg; u8 update_mask; - u8 update_val_enable; + u8 update_val; + u8 update_val_idle; + u8 update_val_normal; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; int const *voltages; int voltages_len; unsigned int delay; + enum ab8500_pin gpio_pin; }; /* voltage tables for the vauxn/vintcore supplies */ @@ -112,15 +123,17 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, - info->update_mask, info->update_val_enable); + info->update_mask, info->update_val); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); + info->is_enabled = true; + dev_vdbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", info->desc.name, info->update_bank, info->update_reg, - info->update_mask, info->update_val_enable); + info->update_mask, info->update_val); return ret; } @@ -142,6 +155,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); + info->is_enabled = false; + dev_vdbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value): 0x%x, 0x%x, 0x%x, 0x%x\n", info->desc.name, info->update_bank, info->update_reg, @@ -150,6 +165,88 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) return ret; } +static unsigned int ab8500_regulator_get_optimum_mode( + struct regulator_dev *rdev, int input_uV, + int output_uV, int load_uA) +{ + 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; + } + + if (load_uA <= info->load_lp_uA) + mode = REGULATOR_MODE_IDLE; + else + mode = REGULATOR_MODE_NORMAL; + + return mode; +} + +static int ab8500_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int ret = 0; + + 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; + } + + switch (mode) { + case REGULATOR_MODE_NORMAL: + info->update_val = info->update_val_normal; + break; + case REGULATOR_MODE_IDLE: + info->update_val = info->update_val_idle; + break; + default: + return -EINVAL; + } + + if (info->is_enabled) { + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, + info->update_mask, info->update_val); + if (ret < 0) + dev_err(rdev_get_dev(rdev), + "couldn't set regulator mode\n"); + + dev_vdbg(rdev_get_dev(rdev), + "%s-set_mode (bank, reg, mask, value): " + "0x%x, 0x%x, 0x%x, 0x%x\n", + info->desc.name, info->update_bank, info->update_reg, + info->update_mask, info->update_val); + } + + return ret; +} + +static unsigned int ab8500_regulator_get_mode(struct regulator_dev *rdev) +{ + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + int ret; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + if (info->update_val == info->update_val_normal) + ret = REGULATOR_MODE_NORMAL; + else if (info->update_val == 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; @@ -176,9 +273,11 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) info->update_mask, regval); if (regval & info->update_mask) - return true; + info->is_enabled = true; else - return false; + info->is_enabled = false; + + return info->is_enabled; } static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) @@ -274,8 +373,13 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, *selector = ret; + /* vintcore register has a different layout */ + if (info->desc.id == AB8500_LDO_INTCORE) + regval = ((u8)ret) << 3; + else + regval = (u8)ret; + /* set the registers for the request */ - regval = (u8)ret; ret = abx500_mask_and_set_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, info->voltage_mask, regval); @@ -315,9 +419,12 @@ static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev, return info->delay; } -static struct regulator_ops ab8500_regulator_ops = { +static struct regulator_ops ab8500_regulator_volt_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .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, @@ -338,16 +445,115 @@ static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) return info->fixed_uV; } -static struct regulator_ops ab8500_regulator_fixed_ops = { +static struct regulator_ops ab8500_regulator_mode_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, + .get_optimum_mode = ab8500_regulator_get_optimum_mode, + .set_mode = ab8500_regulator_set_mode, + .get_mode = ab8500_regulator_get_mode, .get_voltage = ab8500_fixed_get_voltage, .list_voltage = ab8500_list_voltage, .enable_time = ab8500_regulator_enable_time, .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel, }; +static struct regulator_ops ab8500_regulator_ops = { + .enable = ab8500_regulator_enable, + .disable = ab8500_regulator_disable, + .is_enabled = ab8500_regulator_is_enabled, + .get_voltage = ab8500_fixed_get_voltage, + .list_voltage = ab8500_list_voltage, +}; + +static int ab8500_sysclkreq_enable(struct regulator_dev *rdev) +{ + int ret; + 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; + } + + ret = ab8500_gpio_config_select(info->dev, info->gpio_pin, false); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't set sysclkreq pin selection\n"); + return ret; + } + + info->is_enabled = true; + + dev_vdbg(rdev_get_dev(rdev), + "%s-enable (gpio_pin, gpio_select): %i, false\n", + info->desc.name, info->gpio_pin); + + return ret; +} + +static int ab8500_sysclkreq_disable(struct regulator_dev *rdev) +{ + int ret; + 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; + } + + ret = ab8500_gpio_config_select(info->dev, info->gpio_pin, true); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't set gpio pin selection\n"); + return ret; + } + + info->is_enabled = false; + + dev_vdbg(rdev_get_dev(rdev), + "%s-disable (gpio_pin, gpio_select): %i, true\n", + info->desc.name, info->gpio_pin); + + return ret; +} + +static int ab8500_sysclkreq_is_enabled(struct regulator_dev *rdev) +{ + int ret; + struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + bool gpio_select; + + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); + return -EINVAL; + } + + ret = ab8500_gpio_config_get_select(info->dev, info->gpio_pin, + &gpio_select); + if (ret < 0) { + dev_err(rdev_get_dev(rdev), + "couldn't read gpio pin selection\n"); + return ret; + } + + info->is_enabled = !gpio_select; + + dev_vdbg(rdev_get_dev(rdev), + "%s-is_enabled (gpio_pin, is_enabled): %i, %i\n", + info->desc.name, info->gpio_pin, !gpio_select); + + return info->is_enabled; +} + +static struct regulator_ops ab8500_sysclkreq_ops = { + .enable = ab8500_sysclkreq_enable, + .disable = ab8500_sysclkreq_disable, + .is_enabled = ab8500_sysclkreq_is_enabled, + .get_voltage = ab8500_fixed_get_voltage, + .list_voltage = ab8500_list_voltage, +}; + static struct ab8500_regulator_info ab8500_regulator_info[AB8500_NUM_REGULATORS] = { /* @@ -359,7 +565,7 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX1] = { .desc = { .name = "LDO-AUX1", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX1, .owner = THIS_MODULE, @@ -367,10 +573,13 @@ static struct ab8500_regulator_info }, .min_uV = 1100000, .max_uV = 3300000, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, .voltage_bank = 0x04, .voltage_reg = 0x1f, .voltage_mask = 0x0f, @@ -380,7 +589,7 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX2] = { .desc = { .name = "LDO-AUX2", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX2, .owner = THIS_MODULE, @@ -388,10 +597,13 @@ static struct ab8500_regulator_info }, .min_uV = 1100000, .max_uV = 3300000, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x09, .update_mask = 0x0c, - .update_val_enable = 0x04, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, .voltage_bank = 0x04, .voltage_reg = 0x20, .voltage_mask = 0x0f, @@ -401,7 +613,7 @@ static struct ab8500_regulator_info [AB8500_LDO_AUX3] = { .desc = { .name = "LDO-AUX3", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUX3, .owner = THIS_MODULE, @@ -409,10 +621,13 @@ static struct ab8500_regulator_info }, .min_uV = 1100000, .max_uV = 3300000, + .load_lp_uA = 5000, .update_bank = 0x04, .update_reg = 0x0a, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, .voltage_bank = 0x04, .voltage_reg = 0x21, .voltage_mask = 0x07, @@ -422,7 +637,7 @@ static struct ab8500_regulator_info [AB8500_LDO_INTCORE] = { .desc = { .name = "LDO-INTCORE", - .ops = &ab8500_regulator_ops, + .ops = &ab8500_regulator_volt_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_INTCORE, .owner = THIS_MODULE, @@ -430,10 +645,13 @@ static struct ab8500_regulator_info }, .min_uV = 1100000, .max_uV = 3300000, + .load_lp_uA = 5000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x44, - .update_val_enable = 0x04, + .update_val = 0x44, + .update_val_idle = 0x44, + .update_val_normal = 0x04, .voltage_bank = 0x03, .voltage_reg = 0x80, .voltage_mask = 0x38, @@ -449,7 +667,7 @@ static struct ab8500_regulator_info [AB8500_LDO_TVOUT] = { .desc = { .name = "LDO-TVOUT", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_TVOUT, .owner = THIS_MODULE, @@ -457,15 +675,18 @@ static struct ab8500_regulator_info }, .delay = 10000, .fixed_uV = 2000000, + .load_lp_uA = 1000, .update_bank = 0x03, .update_reg = 0x80, .update_mask = 0x82, - .update_val_enable = 0x02, + .update_val = 0x02, + .update_val_idle = 0x82, + .update_val_normal = 0x02, }, [AB8500_LDO_USB] = { .desc = { .name = "LDO-USB", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_USB, .owner = THIS_MODULE, @@ -475,12 +696,14 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x82, .update_mask = 0x03, - .update_val_enable = 0x01, + .update_val = 0x01, + .update_val_idle = 0x03, + .update_val_normal = 0x01, }, [AB8500_LDO_AUDIO] = { .desc = { .name = "LDO-AUDIO", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_AUDIO, .owner = THIS_MODULE, @@ -490,12 +713,12 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x02, - .update_val_enable = 0x02, + .update_val = 0x02, }, [AB8500_LDO_ANAMIC1] = { .desc = { .name = "LDO-ANAMIC1", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_ANAMIC1, .owner = THIS_MODULE, @@ -505,12 +728,12 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x08, - .update_val_enable = 0x08, + .update_val = 0x08, }, [AB8500_LDO_ANAMIC2] = { .desc = { .name = "LDO-ANAMIC2", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_ANAMIC2, .owner = THIS_MODULE, @@ -520,12 +743,12 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x10, - .update_val_enable = 0x10, + .update_val = 0x10, }, [AB8500_LDO_DMIC] = { .desc = { .name = "LDO-DMIC", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_DMIC, .owner = THIS_MODULE, @@ -535,25 +758,58 @@ static struct ab8500_regulator_info .update_bank = 0x03, .update_reg = 0x83, .update_mask = 0x04, - .update_val_enable = 0x04, + .update_val = 0x04, }, + + /* + * Regulators with fixed voltage and normal/idle modes + */ [AB8500_LDO_ANA] = { .desc = { .name = "LDO-ANA", - .ops = &ab8500_regulator_fixed_ops, + .ops = &ab8500_regulator_mode_ops, .type = REGULATOR_VOLTAGE, .id = AB8500_LDO_ANA, .owner = THIS_MODULE, .n_voltages = 1, }, .fixed_uV = 1200000, + .load_lp_uA = 1000, .update_bank = 0x04, .update_reg = 0x06, .update_mask = 0x0c, - .update_val_enable = 0x04, + .update_val = 0x04, + .update_val_idle = 0x0c, + .update_val_normal = 0x04, }, - + /* + * SysClkReq regulators + */ + [AB8500_SYSCLKREQ_2] = { + .desc = { + .name = "SYSCLKREQ-2", + .ops = &ab8500_sysclkreq_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_SYSCLKREQ_2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1, /* bogus value */ + .gpio_pin = AB8500_PIN_GPIO1, + }, + [AB8500_SYSCLKREQ_4] = { + .desc = { + .name = "SYSCLKREQ-4", + .ops = &ab8500_sysclkreq_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_SYSCLKREQ_4, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1, /* bogus value */ + .gpio_pin = AB8500_PIN_GPIO3, + }, }; struct ab8500_reg_init { @@ -571,11 +827,19 @@ struct ab8500_reg_init { static struct ab8500_reg_init ab8500_reg_init[] = { /* + * 0x03, VarmRequestCtrl + * 0x0c, VapeRequestCtrl + * 0x30, Vsmps1RequestCtrl + * 0xc0, Vsmps2RequestCtrl + */ + REG_INIT(AB8500_REGUREQUESTCTRL1, 0x03, 0x03, 0xff), + /* + * 0x03, Vsmps3RequestCtrl + * 0x0c, VpllRequestCtrl * 0x30, VanaRequestCtrl - * 0x0C, VpllRequestCtrl * 0xc0, VextSupply1RequestCtrl */ - REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xfc), + REG_INIT(AB8500_REGUREQUESTCTRL2, 0x03, 0x04, 0xff), /* * 0x03, VextSupply2RequestCtrl * 0x0c, VextSupply3RequestCtrl @@ -589,57 +853,82 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUREQUESTCTRL4, 0x03, 0x06, 0x07), /* + * 0x01, Vsmps1SysClkReq1HPValid + * 0x02, Vsmps2SysClkReq1HPValid + * 0x04, Vsmps3SysClkReq1HPValid * 0x08, VanaSysClkReq1HPValid + * 0x10, VpllSysClkReq1HPValid * 0x20, Vaux1SysClkReq1HPValid * 0x40, Vaux2SysClkReq1HPValid * 0x80, Vaux3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xe8), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID1, 0x03, 0x07, 0xff), /* + * 0x01, VapeSysClkReq1HPValid + * 0x02, VarmSysClkReq1HPValid + * 0x04, VbbSysClkReq1HPValid + * 0x08, VmodSysClkReq1HPValid * 0x10, VextSupply1SysClkReq1HPValid * 0x20, VextSupply2SysClkReq1HPValid * 0x40, VextSupply3SysClkReq1HPValid */ - REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x70), + REG_INIT(AB8500_REGUSYSCLKREQ1HPVALID2, 0x03, 0x08, 0x7f), /* + * 0x01, Vsmps1HwHPReq1Valid + * 0x02, Vsmps2HwHPReq1Valid + * 0x04, Vsmps3HwHPReq1Valid * 0x08, VanaHwHPReq1Valid + * 0x10, VpllHwHPReq1Valid * 0x20, Vaux1HwHPReq1Valid * 0x40, Vaux2HwHPReq1Valid * 0x80, Vaux3HwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xe8), + REG_INIT(AB8500_REGUHWHPREQ1VALID1, 0x03, 0x09, 0xff), /* * 0x01, VextSupply1HwHPReq1Valid * 0x02, VextSupply2HwHPReq1Valid * 0x04, VextSupply3HwHPReq1Valid + * 0x08, VmodHwHPReq1Valid */ - REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x07), + REG_INIT(AB8500_REGUHWHPREQ1VALID2, 0x03, 0x0a, 0x0f), /* + * 0x01, Vsmps1HwHPReq2Valid + * 0x02, Vsmps2HwHPReq2Valid + * 0x03, Vsmps3HwHPReq2Valid * 0x08, VanaHwHPReq2Valid + * 0x10, VpllHwHPReq2Valid * 0x20, Vaux1HwHPReq2Valid * 0x40, Vaux2HwHPReq2Valid * 0x80, Vaux3HwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xe8), + REG_INIT(AB8500_REGUHWHPREQ2VALID1, 0x03, 0x0b, 0xff), /* * 0x01, VextSupply1HwHPReq2Valid * 0x02, VextSupply2HwHPReq2Valid * 0x04, VextSupply3HwHPReq2Valid + * 0x08, VmodHwHPReq2Valid */ - REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x07), + REG_INIT(AB8500_REGUHWHPREQ2VALID2, 0x03, 0x0c, 0x0f), /* + * 0x01, VapeSwHPReqValid + * 0x02, VarmSwHPReqValid + * 0x04, Vsmps1SwHPReqValid + * 0x08, Vsmps2SwHPReqValid + * 0x10, Vsmps3SwHPReqValid * 0x20, VanaSwHPReqValid + * 0x40, VpllSwHPReqValid * 0x80, Vaux1SwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xa0), + REG_INIT(AB8500_REGUSWHPREQVALID1, 0x03, 0x0d, 0xff), /* * 0x01, Vaux2SwHPReqValid * 0x02, Vaux3SwHPReqValid * 0x04, VextSupply1SwHPReqValid * 0x08, VextSupply2SwHPReqValid * 0x10, VextSupply3SwHPReqValid + * 0x20, VmodSwHPReqValid */ - REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x1f), + REG_INIT(AB8500_REGUSWHPREQVALID2, 0x03, 0x0e, 0x3f), /* * 0x02, SysClkReq2Valid1 * ... @@ -673,8 +962,28 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_REGUCTRL1VAMIC, 0x03, 0x84, 0x03), /* - * 0x0c, VanaRegu + * 0x03, Vsmps1Regu + * 0x0c, Vsmps1SelCtrl + * 0x10, Vsmps1AutoMode + * 0x20, Vsmps1PWMMode + */ + REG_INIT(AB8500_VSMPS1REGU, 0x04, 0x03, 0x3f), + /* + * 0x03, Vsmps2Regu + * 0x0c, Vsmps2SelCtrl + * 0x10, Vsmps2AutoMode + * 0x20, Vsmps2PWMMode + */ + REG_INIT(AB8500_VSMPS2REGU, 0x04, 0x04, 0x3f), + /* + * 0x03, Vsmps3Regu + * 0x0c, Vsmps3SelCtrl + * NOTE! PRCMU register + */ + REG_INIT(AB8500_VSMPS3REGU, 0x04, 0x05, 0x0f), + /* * 0x03, VpllRegu + * 0x0c, VanaRegu */ REG_INIT(AB8500_VPLLVANAREGU, 0x04, 0x06, 0x0f), /* @@ -696,14 +1005,45 @@ static struct ab8500_reg_init ab8500_reg_init[] = { */ REG_INIT(AB8500_VAUX12REGU, 0x04, 0x09, 0x0f), /* + * 0x0c, Vrf1Regu * 0x03, Vaux3Regu */ - REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x03), + REG_INIT(AB8500_VRF1VAUX3REGU, 0x04, 0x0a, 0x0f), /* * 0x3f, Vsmps1Sel1 */ REG_INIT(AB8500_VSMPS1SEL1, 0x04, 0x13, 0x3f), /* + * 0x3f, Vsmps1Sel2 + */ + REG_INIT(AB8500_VSMPS1SEL2, 0x04, 0x14, 0x3f), + /* + * 0x3f, Vsmps1Sel3 + */ + REG_INIT(AB8500_VSMPS1SEL3, 0x04, 0x15, 0x3f), + /* + * 0x3f, Vsmps2Sel1 + */ + REG_INIT(AB8500_VSMPS2SEL1, 0x04, 0x17, 0x3f), + /* + * 0x3f, Vsmps2Sel2 + */ + REG_INIT(AB8500_VSMPS2SEL2, 0x04, 0x18, 0x3f), + /* + * 0x3f, Vsmps2Sel3 + */ + REG_INIT(AB8500_VSMPS2SEL3, 0x04, 0x19, 0x3f), + /* + * 0x7f, Vsmps3Sel1 + * NOTE! PRCMU register + */ + REG_INIT(AB8500_VSMPS3SEL1, 0x04, 0x1b, 0x7f), + /* + * 0x7f, Vsmps3Sel2 + * NOTE! PRCMU register + */ + REG_INIT(AB8500_VSMPS3SEL2, 0x04, 0x1c, 0x7f), + /* * 0x0f, Vaux1Sel */ REG_INIT(AB8500_VAUX1SEL, 0x04, 0x1f, 0x0f), @@ -713,13 +1053,16 @@ static struct ab8500_reg_init ab8500_reg_init[] = { REG_INIT(AB8500_VAUX2SEL, 0x04, 0x20, 0x0f), /* * 0x07, Vaux3Sel + * 0x30, Vrf1Sel */ - REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x07), + REG_INIT(AB8500_VRF1VAUX3SEL, 0x04, 0x21, 0x37), /* * 0x01, VextSupply12LP */ REG_INIT(AB8500_REGUCTRL2SPARE, 0x04, 0x22, 0x01), /* + * 0x01, VpllDisch + * 0x02, Vrf1Disch * 0x04, Vaux1Disch * 0x08, Vaux2Disch * 0x10, Vaux3Disch @@ -727,26 +1070,36 @@ static struct ab8500_reg_init ab8500_reg_init[] = { * 0x40, VTVoutDisch * 0x80, VaudioDisch */ - REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xfc), + REG_INIT(AB8500_REGUCTRLDISCH, 0x04, 0x43, 0xff), /* + * 0x01, VsimDisch * 0x02, VanaDisch * 0x04, VdmicPullDownEna + * 0x08, VpllPullDownEna * 0x10, VdmicDisch */ - REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x16), + REG_INIT(AB8500_REGUCTRLDISCH2, 0x04, 0x44, 0x1f), }; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); - struct ab8500_platform_data *pdata; + struct ab8500_platform_data *ppdata; + struct ab8500_regulator_platform_data *pdata; int i, err; if (!ab8500) { dev_err(&pdev->dev, "null mfd parent\n"); return -EINVAL; } - pdata = dev_get_platdata(ab8500->dev); + + ppdata = dev_get_platdata(ab8500->dev); + if (!ppdata) { + dev_err(&pdev->dev, "null parent pdata\n"); + return -EINVAL; + } + + pdata = ppdata->regulator; if (!pdata) { dev_err(&pdev->dev, "null pdata\n"); return -EINVAL; @@ -759,31 +1112,24 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } /* initialize registers */ - for (i = 0; i < pdata->num_regulator_reg_init; i++) { + for (i = 0; i < pdata->num_reg_init; i++) { int id; - u8 value; + u8 mask, value; - id = pdata->regulator_reg_init[i].id; - value = pdata->regulator_reg_init[i].value; + id = pdata->reg_init[i].id; + mask = pdata->reg_init[i].mask; + value = pdata->reg_init[i].value; /* check for configuration errors */ - if (id >= AB8500_NUM_REGULATOR_REGISTERS) { - dev_err(&pdev->dev, - "Configuration error: id outside range.\n"); - return -EINVAL; - } - if (value & ~ab8500_reg_init[id].mask) { - dev_err(&pdev->dev, - "Configuration error: value outside mask.\n"); - return -EINVAL; - } + BUG_ON(id >= AB8500_NUM_REGULATOR_REGISTERS); + BUG_ON(value & ~mask); + BUG_ON(mask & ~ab8500_reg_init[id].mask); /* initialize register */ err = abx500_mask_and_set_register_interruptible(&pdev->dev, ab8500_reg_init[id].bank, ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + mask, value); if (err < 0) { dev_err(&pdev->dev, "Failed to initialize 0x%02x, 0x%02x.\n", @@ -795,10 +1141,32 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) " init: 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", ab8500_reg_init[id].bank, ab8500_reg_init[id].addr, - ab8500_reg_init[id].mask, - value); + mask, value); } + /* + * This changes the default setting for VextSupply3Regu to low power. + * Active high or low is depending on OTP which is changed from ab8500v3.0. + * Remove this when ab8500v2.0 is no longer important. + * This only affects power consumption and it depends on the + * HREF OTP configurations. + */ + if (abx500_get_chip_id(&pdev->dev) < 0x30) { + err = abx500_mask_and_set_register_interruptible(&pdev->dev, + AB8500_REGU_CTRL2, 0x08, 0x30, 0x30); + if (err < 0) { + dev_err(&pdev->dev, + "Failed to override 0x%02x, 0x%02x.\n", + AB8500_REGU_CTRL2, 0x08); + return err; + } + } + + /* register external regulators (before Vaux1, 2 and 3) */ + err = ab8500_ext_regulator_init(pdev); + if (err) + return err; + /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; @@ -843,7 +1211,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) static __devexit int ab8500_regulator_remove(struct platform_device *pdev) { - int i; + int i, err; for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; @@ -855,6 +1223,11 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) regulator_unregister(info->regulator); } + /* remove external regulators (after Vaux1, 2 and 3) */ + err = ab8500_ext_regulator_exit(pdev); + if (err) + return err; + return 0; } @@ -887,5 +1260,6 @@ module_exit(ab8500_regulator_exit); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Sundar Iyer <sundar.iyer@stericsson.com>"); +MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>"); MODULE_DESCRIPTION("Regulator Driver for ST-Ericsson AB8500 Mixed-Sig PMIC"); MODULE_ALIAS("platform:ab8500-regulator"); |