From 63cee946148821bca42be10130b061c2d0f5af7e Mon Sep 17 00:00:00 2001 From: Mattias Wallin Date: Thu, 4 Nov 2010 11:01:31 +0100 Subject: regulator: lock supply in regulator enable This patch add locks around regulator supply enable. Signed-off-by: Mattias Wallin Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ba521f0..81336e2 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1267,17 +1267,15 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - if (rdev->use_count == 0) { - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - mutex_lock(&rdev->supply->mutex); - ret = _regulator_enable(rdev->supply); - mutex_unlock(&rdev->supply->mutex); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; - } + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; } } -- cgit v0.10.2 From 3a93f2a9f4d8f73d74c0e552feb68a10f778a219 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Nov 2010 14:38:29 +0000 Subject: regulator: Report actual configured voltage to set_voltage() Change the interface used by set_voltage() to report the selected value to the regulator core in terms of a selector used by list_voltage(). This allows the regulator core to know the voltage that was chosen without having to do an explict get_voltage(), which would be much more expensive as it will generally access hardware. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 2ce2eb7..dd63084 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -249,7 +249,7 @@ static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) } static int pm8607_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); uint8_t val, mask; @@ -263,6 +263,7 @@ static int pm8607_set_voltage(struct regulator_dev *rdev, ret = choose_voltage(rdev, min_uV, max_uV); if (ret < 0) return -EINVAL; + *selector = ret; val = (uint8_t)(ret << info->vol_shift); mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c index b349266..ed6feaf 100644 --- a/drivers/regulator/ab3100.c +++ b/drivers/regulator/ab3100.c @@ -362,7 +362,8 @@ static int ab3100_get_best_voltage_index(struct regulator_dev *reg, } static int ab3100_set_voltage_regulator(struct regulator_dev *reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct ab3100_regulator *abreg = reg->reg_data; u8 regval; @@ -373,6 +374,8 @@ static int ab3100_set_voltage_regulator(struct regulator_dev *reg, if (bestindex < 0) return bestindex; + *selector = bestindex; + err = abx500_get_register_interruptible(abreg->dev, 0, abreg->regreg, ®val); if (err) { diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index db6b70f..2f4ec0f 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -215,7 +215,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, } static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); @@ -232,6 +233,8 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, return ret; } + *selector = ret; + /* set the registers for the request */ ret = abx500_mask_and_set_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 81336e2..67d3a61 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -723,13 +723,16 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulator_ops *ops = rdev->desc->ops; const char *name = rdev_get_name(rdev); int ret; + unsigned selector; /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && rdev->constraints->min_uV == rdev->constraints->max_uV && ops->set_voltage) { ret = ops->set_voltage(rdev, - rdev->constraints->min_uV, rdev->constraints->max_uV); + rdev->constraints->min_uV, + rdev->constraints->max_uV, + &selector); if (ret < 0) { printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n", __func__, @@ -1625,6 +1628,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret; + unsigned selector; mutex_lock(&rdev->mutex); @@ -1640,7 +1644,13 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) goto out; regulator->min_uV = min_uV; regulator->max_uV = max_uV; - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV); + + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); + + if (rdev->desc->ops->list_voltage) + selector = rdev->desc->ops->list_voltage(rdev, selector); + else + selector = -1; out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index f8c4661..362e082 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -107,7 +107,7 @@ static inline int check_range(struct da903x_regulator_info *info, /* DA9030/DA9034 common operations */ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -119,6 +119,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -187,7 +188,8 @@ static int da903x_list_voltage(struct regulator_dev *rdev, unsigned selector) /* DA9030 specific operations */ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -200,6 +202,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */ @@ -214,7 +217,8 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, } static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da903x_dev = to_da903x_dev(rdev); @@ -234,6 +238,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, val = (min_uV - thresh + info->step_uV - 1) / info->step_uV; } + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -263,7 +268,7 @@ static int da9030_get_ldo14_voltage(struct regulator_dev *rdev) /* DA9034 specific operations */ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -276,6 +281,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; @@ -289,7 +295,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, } static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct da903x_regulator_info *info = rdev_get_drvdata(rdev); struct device *da9034_dev = to_da903x_dev(rdev); @@ -302,6 +308,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; val = (val >= 20) ? val - 12 : ((val > 7) ? 8 : val); + *selector = val; val <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b8cc638..b5639e8 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -58,7 +58,9 @@ out: return data; } -static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) +static int isl6271a_set_voltage(struct regulator_dev *dev, + int minuV, int maxuV, + unsigned *selector) { struct isl_pmic *pmic = rdev_get_drvdata(dev); int vsel, err, data; @@ -78,6 +80,8 @@ static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) /* Convert the microvolts to data for the chip */ data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP; + *selector = data; + mutex_lock(&pmic->mtx); err = i2c_smbus_write_byte(pmic->client, data); diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 3bb82b6..0f22ef1 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -168,7 +168,8 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) } static int lp3971_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; @@ -187,6 +188,8 @@ static int lp3971_ldo_set_voltage(struct regulator_dev *dev, if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + return lp3971_set_bits(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo), LDO_VOL_CONTR_MASK << LDO_VOL_CONTR_SHIFT(ldo), val << LDO_VOL_CONTR_SHIFT(ldo)); @@ -256,7 +259,8 @@ static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; @@ -277,6 +281,8 @@ static int lp3971_dcdc_set_voltage(struct regulator_dev *dev, if (val > BUCK_TARGET_VOL_MAX_IDX || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3971_set_bits(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck), BUCK_TARGET_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index e07062f..6aa1b50 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -292,7 +292,8 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) } static int lp3972_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; @@ -313,6 +314,8 @@ static int lp3972_ldo_set_voltage(struct regulator_dev *dev, if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) return -EINVAL; + *selector = val; + shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); @@ -416,7 +419,8 @@ static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) } static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; @@ -438,6 +442,8 @@ static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, vol_map[val] > max_vol) return -EINVAL; + *selector = val; + ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), LP3972_BUCK_VOL_MASK, val); if (ret) diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index 559cfa2..3f49512 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -63,12 +63,12 @@ static int max1586_v3_calc_voltage(struct max1586_data *max1586, return max1586->min_uV + (selector * range_uV / MAX1586_V3_MAX_VSEL); } -static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct max1586_data *max1586 = rdev_get_drvdata(rdev); struct i2c_client *client = max1586->client; unsigned range_uV = max1586->max_uV - max1586->min_uV; - unsigned selector; u8 v3_prog; if (min_uV > max1586->max_uV || max_uV < max1586->min_uV) @@ -76,15 +76,15 @@ static int max1586_v3_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (min_uV < max1586->min_uV) min_uV = max1586->min_uV; - selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + + *selector = ((min_uV - max1586->min_uV) * MAX1586_V3_MAX_VSEL + range_uV - 1) / range_uV; - if (max1586_v3_calc_voltage(max1586, selector) > max_uV) + if (max1586_v3_calc_voltage(max1586, *selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v3 to %dmv\n", - max1586_v3_calc_voltage(max1586, selector) / 1000); + max1586_v3_calc_voltage(max1586, *selector) / 1000); - v3_prog = I2C_V3_SELECT | (u8) selector; + v3_prog = I2C_V3_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v3_prog); } @@ -110,10 +110,10 @@ static int max1586_v6_calc_voltage(unsigned selector) return voltages_uv[selector]; } -static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *selector) { struct i2c_client *client = rdev_get_drvdata(rdev); - unsigned selector; u8 v6_prog; if (min_uV < MAX1586_V6_MIN_UV || min_uV > MAX1586_V6_MAX_UV) @@ -122,21 +122,21 @@ static int max1586_v6_set(struct regulator_dev *rdev, int min_uV, int max_uV) return -EINVAL; if (min_uV < 1800000) - selector = 0; + *selector = 0; else if (min_uV < 2500000) - selector = 1; + *selector = 1; else if (min_uV < 3000000) - selector = 2; + *selector = 2; else if (min_uV >= 3000000) - selector = 3; + *selector = 3; - if (max1586_v6_calc_voltage(selector) > max_uV) + if (max1586_v6_calc_voltage(*selector) > max_uV) return -EINVAL; dev_dbg(&client->dev, "changing voltage v6 to %dmv\n", - max1586_v6_calc_voltage(selector) / 1000); + max1586_v6_calc_voltage(*selector) / 1000); - v6_prog = I2C_V6_SELECT | (u8) selector; + v6_prog = I2C_V6_SELECT | (u8) *selector; return i2c_smbus_write_byte(client, v6_prog); } diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c index 6b60a9c..30eb9e5 100644 --- a/drivers/regulator/max8649.c +++ b/drivers/regulator/max8649.c @@ -155,7 +155,7 @@ static int max8649_get_voltage(struct regulator_dev *rdev) } static int max8649_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8649_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -168,6 +168,7 @@ static int max8649_set_voltage(struct regulator_dev *rdev, data = (min_uV - MAX8649_DCDC_VMIN + MAX8649_DCDC_STEP - 1) / MAX8649_DCDC_STEP; mask = MAX8649_VOL_MASK; + *selector = data & mask; return max8649_set_bits(info->i2c, info->vol_reg, mask, data); } diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index c570e6e..33f5d9a 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -141,7 +141,8 @@ static int max8660_dcdc_get(struct regulator_dev *rdev) return MAX8660_DCDC_MIN_UV + selector * MAX8660_DCDC_STEP; } -static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 reg, selector, bits; @@ -154,6 +155,7 @@ static int max8660_dcdc_set(struct regulator_dev *rdev, int min_uV, int max_uV) selector = (min_uV - (MAX8660_DCDC_MIN_UV - MAX8660_DCDC_STEP + 1)) / MAX8660_DCDC_STEP; + *s = selector; ret = max8660_dcdc_list(rdev, selector); if (ret < 0 || ret > max_uV) @@ -196,7 +198,8 @@ static int max8660_ldo5_get(struct regulator_dev *rdev) return MAX8660_LDO5_MIN_UV + selector * MAX8660_LDO5_STEP; } -static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -213,6 +216,8 @@ static int max8660_ldo5_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + ret = max8660_write(max8660, MAX8660_MDTV2, 0, selector); if (ret) return ret; @@ -270,7 +275,8 @@ static int max8660_ldo67_get(struct regulator_dev *rdev) return MAX8660_LDO67_MIN_UV + selector * MAX8660_LDO67_STEP; } -static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) +static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned int *s) { struct max8660 *max8660 = rdev_get_drvdata(rdev); u8 selector; @@ -288,6 +294,8 @@ static int max8660_ldo67_set(struct regulator_dev *rdev, int min_uV, int max_uV) if (ret < 0 || ret > max_uV) return -EINVAL; + *s = selector; + if (rdev_get_id(rdev) == MAX8660_V6) return max8660_write(max8660, MAX8660_L12VCR, 0xf0, selector); else diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index 552cad8..8ae1475 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -55,7 +55,7 @@ static int max8925_list_voltage(struct regulator_dev *rdev, unsigned index) } static int max8925_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned int *selector) { struct max8925_regulator_info *info = rdev_get_drvdata(rdev); unsigned char data, mask; @@ -66,6 +66,7 @@ static int max8925_set_voltage(struct regulator_dev *rdev, return -EINVAL; } data = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV; + *selector = data; data <<= info->vol_shift; mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 0d5dda4..a8f4ecf 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -133,7 +133,7 @@ static int max8952_get_voltage(struct regulator_dev *rdev) } static int max8952_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8952_data *max8952 = rdev_get_drvdata(rdev); s8 vid = -1, i; @@ -156,6 +156,7 @@ static int max8952_set_voltage(struct regulator_dev *rdev, if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { max8952->vid0 = (vid % 2 == 1); max8952->vid1 = (((vid >> 1) % 2) == 1); + *selector = vid; gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); } else diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index 5c20756..cb28cf8 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -304,7 +304,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) } static int max8998_set_voltage_ldo(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct i2c_client *i2c = max8998->iodev->i2c; @@ -331,6 +331,8 @@ static int max8998_set_voltage_ldo(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; @@ -352,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v) } static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, int *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = @@ -384,6 +386,8 @@ static int max8998_set_voltage_buck(struct regulator_dev *rdev, if (desc->min + desc->step*i > max_vol) return -EINVAL; + *selector = i; + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); if (ret) return ret; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index ecd99f5..47ea999 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -373,7 +373,8 @@ static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, } static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); int value, id = rdev_get_id(rdev); @@ -388,6 +389,8 @@ static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, if (value < 0) return value; + *selector = value; + mc13783_lock(priv->mc13783); ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, mc13783_regulators[id].vsel_mask, @@ -433,13 +436,16 @@ static struct regulator_ops mc13783_regulator_ops = { }; static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned int *selector) { int id = rdev_get_id(rdev); dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", __func__, id, min_uV, max_uV); + *selector = 0; + if (min_uV >= mc13783_regulators[id].voltages[0] && max_uV <= mc13783_regulators[id].voltages[0]) return 0; diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 29d0566..8dca116 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -151,7 +151,8 @@ static struct pcap_regulator vreg_table[] = { }; static int pcap_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsiged *selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); @@ -170,10 +171,12 @@ static int pcap_regulator_set_voltage(struct regulator_dev *rdev, i = 0; uV = vreg->voltage_table[i] * 1000; - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = i; return ezx_pcap_set_bits(pcap, vreg->reg, (vreg->n_voltages - 1) << vreg->index, i << vreg->index); + } if (i == 0 && rdev_get_id(rdev) == V1) i = vreg->n_voltages - 1; diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index c8f41dc..69a11d9 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -108,7 +108,8 @@ static unsigned int ldo_voltage_value(u8 bits) } static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct pcf50633 *pcf; int regulator_id, millivolts; @@ -147,6 +148,8 @@ static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, return -EINVAL; } + *selector = volt_bits; + return pcf50633_reg_write(pcf, regnr, volt_bits); } diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index cd6d4fc..60a7ca5 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -321,7 +321,8 @@ static int tps65023_dcdc_get_voltage(struct regulator_dev *dev) } static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int dcdc = rdev_get_id(dev); @@ -346,6 +347,8 @@ static int tps65023_dcdc_set_voltage(struct regulator_dev *dev, break; } + *selector = vsel; + /* write to the register in case we found a match */ if (vsel == tps->info[dcdc]->table_len) return -EINVAL; @@ -371,7 +374,7 @@ static int tps65023_ldo_get_voltage(struct regulator_dev *dev) } static int tps65023_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -396,6 +399,8 @@ static int tps65023_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps_65023_reg_read(tps, TPS65023_REG_LDO_CTRL); if (data < 0) return data; diff --git a/drivers/regulator/tps6507x-regulator.c b/drivers/regulator/tps6507x-regulator.c index 020f587..0647552 100644 --- a/drivers/regulator/tps6507x-regulator.c +++ b/drivers/regulator/tps6507x-regulator.c @@ -369,7 +369,8 @@ static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, dcdc = rdev_get_id(dev); @@ -415,6 +416,8 @@ static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[dcdc]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; @@ -450,7 +453,8 @@ static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev) } static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct tps6507x_pmic *tps = rdev_get_drvdata(dev); int data, vsel, ldo = rdev_get_id(dev); @@ -483,6 +487,8 @@ static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev, if (vsel == tps->info[ldo]->table_len) return -EINVAL; + *selector = vsel; + data = tps6507x_pmic_reg_read(tps, reg); if (data < 0) return data; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 6d20b04..bb04a75 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -85,7 +85,8 @@ static int tps6586x_ldo_list_voltage(struct regulator_dev *rdev, static int __tps6586x_ldo_set_voltage(struct device *parent, struct tps6586x_regulator *ri, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { int val, uV; uint8_t mask; @@ -100,6 +101,8 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, /* use the first in-range value */ if (min_uV <= uV && uV <= max_uV) { + *selector = val; + val <<= ri->volt_shift; mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift; @@ -111,12 +114,13 @@ static int __tps6586x_ldo_set_voltage(struct device *parent, } static int tps6586x_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); - return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + return __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); } static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) @@ -140,13 +144,14 @@ static int tps6586x_ldo_get_voltage(struct regulator_dev *rdev) } static int tps6586x_dvm_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); struct device *parent = to_tps6586x_dev(rdev); int ret; - ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV); + ret = __tps6586x_ldo_set_voltage(parent, ri, min_uV, max_uV, + selector); if (ret) return ret; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index a57262a..bd332cf 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -329,7 +329,8 @@ static int twl4030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -345,9 +346,11 @@ twl4030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) /* REVISIT for VAUX2, first match may not be best/lowest */ /* use the first in-range value */ - if (min_uV <= uV && uV <= max_uV) + if (min_uV <= uV && uV <= max_uV) { + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); + } } return -EDOM; @@ -389,7 +392,8 @@ static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) } static int -twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) +twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel; @@ -402,6 +406,7 @@ twl6030ldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) * mV = 1000mv + 100mv * (vsel - 1) */ vsel = (min_uV/1000 - 1000)/100 + 1; + *selector = vsel; return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, vsel); } diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index dbfaf59..71da6b2 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -302,7 +302,7 @@ static int wm831x_buckv_set_dvs(struct regulator_dev *rdev, int state) } static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -314,6 +314,8 @@ static int wm831x_buckv_set_voltage(struct regulator_dev *rdev, if (vsel < 0) return vsel; + *selector = vsel; + /* If this value is already set then do a GPIO update if we can */ if (dcdc->dvs_gpio && dcdc->on_vsel == vsel) return wm831x_buckv_set_dvs(rdev, 0); @@ -636,7 +638,7 @@ static int wm831x_buckp_list_voltage(struct regulator_dev *rdev, } static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, int *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -650,16 +652,20 @@ static int wm831x_buckp_set_voltage_int(struct regulator_dev *rdev, int reg, if (wm831x_buckp_list_voltage(rdev, vsel) > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_DC3_ON_VSEL_MASK, vsel); } static int wm831x_buckp_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_ON_CONFIG; - return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_buckp_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, @@ -667,8 +673,9 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); u16 reg = dcdc->base + WM831X_DCDC_SLEEP_CONTROL; + unsigned selector; - return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV); + return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9edf8f6..9594e71 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -113,7 +113,8 @@ static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -133,16 +134,20 @@ static int wm831x_gp_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, vsel); } static int wm831x_gp_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -150,8 +155,9 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) @@ -413,7 +419,8 @@ static int wm831x_aldo_list_voltage(struct regulator_dev *rdev, } static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -433,16 +440,19 @@ static int wm831x_aldo_set_voltage_int(struct regulator_dev *rdev, int reg, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, vsel); } static int wm831x_aldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_ON_CONTROL; - return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_aldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -450,8 +460,9 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_LDO_SLEEP_CONTROL; + unsigned int selector; - return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) @@ -666,7 +677,8 @@ static int wm831x_alive_ldo_list_voltage(struct regulator_dev *rdev, static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, int reg, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -680,16 +692,20 @@ static int wm831x_alive_ldo_set_voltage_int(struct regulator_dev *rdev, if (ret < min_uV || ret > max_uV) return -EINVAL; + *selector = vsel; + return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, vsel); } static int wm831x_alive_ldo_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, + unsigned *selector) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, min_uV, max_uV, + selector); } static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, @@ -697,8 +713,9 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); int reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL; + unsigned selector; - return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV); + return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index fe4b8a8..7e45b0d 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -360,7 +360,7 @@ int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode, EXPORT_SYMBOL_GPL(wm8350_isink_set_flash); static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev), mV, @@ -397,6 +397,8 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all DCDCs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); @@ -754,7 +756,7 @@ static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev) } static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, - int max_uV) + int max_uV, unsigned *selector) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000, @@ -797,6 +799,8 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, return -EINVAL; } + *selector = mV; + /* all LDOs have same mV bits */ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK; wm8350_reg_write(wm8350, volt_reg, val | mV); diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c index 924c7eb..b42d01c 100644 --- a/drivers/regulator/wm8400-regulator.c +++ b/drivers/regulator/wm8400-regulator.c @@ -67,7 +67,7 @@ static int wm8400_ldo_get_voltage(struct regulator_dev *dev) } static int wm8400_ldo_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -93,6 +93,8 @@ static int wm8400_ldo_set_voltage(struct regulator_dev *dev, val += 0xf; } + *selector = val; + return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev), WM8400_LDO1_VSEL_MASK, val); } @@ -156,7 +158,7 @@ static int wm8400_dcdc_get_voltage(struct regulator_dev *dev) } static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *selector) { struct wm8400 *wm8400 = rdev_get_drvdata(dev); u16 val; @@ -171,6 +173,8 @@ static int wm8400_dcdc_set_voltage(struct regulator_dev *dev, return -EINVAL; BUG_ON(850000 + (25000 * val) < min_uV); + *selector = val; + return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset, WM8400_DC1_VSEL_MASK, val); } diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 03713bc..1b162e6 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -101,7 +101,7 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) } static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; @@ -111,6 +111,7 @@ static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO1_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_1, @@ -152,7 +153,7 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) } static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV) + int min_uV, int max_uV, unsigned *s) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int selector, v; @@ -162,6 +163,7 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, if (v < 0 || v > max_uV) return -EINVAL; + *s = selector; selector <<= WM8994_LDO2_VSEL_SHIFT; return wm8994_set_bits(ldo->wm8994, WM8994_LDO_2, diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 592cd7c..4275cd4 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -79,7 +79,8 @@ struct regulator_ops { int (*list_voltage) (struct regulator_dev *, unsigned selector); /* get/set regulator voltage */ - int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV); + int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, + unsigned *selector); int (*get_voltage) (struct regulator_dev *); /* get/set regulator current */ -- cgit v0.10.2 From 02fa3ec01a0df7a8ccc356d8e245a9a1423b3596 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 10 Nov 2010 14:38:30 +0000 Subject: regulator: Add basic trace facilities Provide some basic trace facilities to the regulator API. We generate events on regulator enable, disable and voltage setting over the actual hardware operations (which are assumed to be the expensive ones which require interaction with the actual device). This is intended to facilitate debug of the performance and behaviour with consumers allowing unified traces to be generated including the regulator operations within the context of the other components of the system. For enable we log the explicit delay for the voltage ramp separately to the interaction with the hardware to highlight the time consumed in I/O. We should add a similar delay for voltage changes, though there the relatively small magnitude of the changes in the context of the I/O costs makes it much less critical for most regulators. Only hardware interactions are currently traced as the primary focus is on the performance and synchronisation of actual hardware interactions. Additional tracepoints for debugging of the logical operations can be added later if required. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 67d3a61..8a5d0ae 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -25,6 +25,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "dummy.h" #define REGULATOR_VERSION "0.5" @@ -1310,6 +1313,8 @@ static int _regulator_enable(struct regulator_dev *rdev) delay = 0; } + trace_regulator_enable(rdev_get_name(rdev)); + /* Allow the regulator to ramp; it would be useful * to extend this for bulk operations so that the * regulators can ramp together. */ @@ -1317,6 +1322,8 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; + trace_regulator_enable_delay(rdev_get_name(rdev)); + if (delay >= 1000) { mdelay(delay / 1000); udelay(delay % 1000); @@ -1324,6 +1331,8 @@ static int _regulator_enable(struct regulator_dev *rdev) udelay(delay); } + trace_regulator_enable_complete(rdev_get_name(rdev)); + } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", __func__, rdev_get_name(rdev), ret); @@ -1379,6 +1388,8 @@ static int _regulator_disable(struct regulator_dev *rdev, /* we are last user */ if (_regulator_can_change_status(rdev) && rdev->desc->ops->disable) { + trace_regulator_disable(rdev_get_name(rdev)); + ret = rdev->desc->ops->disable(rdev); if (ret < 0) { printk(KERN_ERR "%s: failed to disable %s\n", @@ -1386,6 +1397,8 @@ static int _regulator_disable(struct regulator_dev *rdev, return ret; } + trace_regulator_disable_complete(rdev_get_name(rdev)); + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, NULL); } @@ -1645,6 +1658,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) regulator->min_uV = min_uV; regulator->max_uV = max_uV; + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); if (rdev->desc->ops->list_voltage) @@ -1652,6 +1667,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) else selector = -1; + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); mutex_unlock(&rdev->mutex); diff --git a/include/trace/events/regulator.h b/include/trace/events/regulator.h new file mode 100644 index 0000000..37502a7 --- /dev/null +++ b/include/trace/events/regulator.h @@ -0,0 +1,141 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM regulator + +#if !defined(_TRACE_REGULATOR_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_REGULATOR_H + +#include +#include + +/* + * Events which just log themselves and the regulator name for enable/disable + * type tracking. + */ +DECLARE_EVENT_CLASS(regulator_basic, + + TP_PROTO(const char *name), + + TP_ARGS(name), + + TP_STRUCT__entry( + __string( name, name ) + ), + + TP_fast_assign( + __assign_str(name, name); + ), + + TP_printk("name=%s", __get_str(name)) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable_delay, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_enable_complete, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_disable, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +DEFINE_EVENT(regulator_basic, regulator_disable_complete, + + TP_PROTO(const char *name), + + TP_ARGS(name) + +); + +/* + * Events that take a range of numerical values, mostly for voltages + * and so on. + */ +DECLARE_EVENT_CLASS(regulator_range, + + TP_PROTO(const char *name, int min, int max), + + TP_ARGS(name, min, max), + + TP_STRUCT__entry( + __string( name, name ) + __field( int, min ) + __field( int, max ) + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->min = min; + __entry->max = max; + ), + + TP_printk("name=%s (%d-%d)", __get_str(name), + (int)__entry->min, (int)__entry->max) +); + +DEFINE_EVENT(regulator_range, regulator_set_voltage, + + TP_PROTO(const char *name, int min, int max), + + TP_ARGS(name, min, max) + +); + + +/* + * Events that take a single value, mostly for readback and refcounts. + */ +DECLARE_EVENT_CLASS(regulator_value, + + TP_PROTO(const char *name, unsigned int val), + + TP_ARGS(name, val), + + TP_STRUCT__entry( + __string( name, name ) + __field( unsigned int, val ) + ), + + TP_fast_assign( + __assign_str(name, name); + __entry->val = val; + ), + + TP_printk("name=%s, val=%u", __get_str(name), + (int)__entry->val) +); + +DEFINE_EVENT(regulator_value, regulator_set_voltage_complete, + + TP_PROTO(const char *name, unsigned int value), + + TP_ARGS(name, value) + +); + +#endif /* _TRACE_POWER_H */ + +/* This part must be outside protection */ +#include -- cgit v0.10.2 From acaf6ffefdf65188071f88664435b86651d70e7c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Wed, 10 Nov 2010 11:06:22 +0100 Subject: regulator: enable supply regulator only when use count is zero Supply regulators are disabled only when the last reference count is removed on the child regulator (the use count goes from 1 to 0). This patch changes the behaviour of enable so the supply regulator is enabled only when the use count of the child regulator goes from 0 to 1. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8a5d0ae..a48cf58 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1273,15 +1273,17 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - mutex_lock(&rdev->supply->mutex); - ret = _regulator_enable(rdev->supply); - mutex_unlock(&rdev->supply->mutex); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; + if (rdev->use_count == 0) { + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; + } } } -- cgit v0.10.2 From 7bed08c56540825ab9c7909a12e9b5bcdafa62ba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 11 Nov 2010 11:57:17 +0000 Subject: regulator: Fix typo in PCAP regulator_set_voltage() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 8dca116..31f6e11 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -152,7 +152,7 @@ static struct pcap_regulator vreg_table[] = { static int pcap_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, - unsiged *selector) + unsigned *selector) { struct pcap_regulator *vreg = &vreg_table[rdev_get_id(rdev)]; void *pcap = rdev_get_drvdata(rdev); -- cgit v0.10.2 From c5e28ed78274468b92522e7f1e9a5e6080559100 Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 17 Nov 2010 15:30:27 -0800 Subject: drivers: regulator: core: use pr_fmt This adds a pr_fmt line which uses the __func__ macro. I also convert the current pr_ lines to remove their __func__ usage. Cc: bleong@codeaurora.org Signed-off-by: Daniel Walker Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a48cf58..7c09063 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,6 +13,8 @@ * */ +#define pr_fmt(fmt) "%s:" fmt, __func__ + #include #include #include @@ -771,8 +773,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "invalid", name); + pr_err("%s '%s' voltage constraints\n", "invalid", + name); return -EINVAL; } @@ -793,22 +795,22 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("%s: %s '%s' voltage constraints\n", - __func__, "unsupportable", name); + pr_err("%s '%s' voltage constraints\n", "unsupportable", + name); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "min_uV", - constraints->min_uV, min_uV); + pr_debug("override '%s' %s, %d -> %d\n", + name, "min_uV", + constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("%s: override '%s' %s, %d -> %d\n", - __func__, name, "max_uV", - constraints->max_uV, max_uV); + pr_debug("override '%s' %s, %d -> %d\n", + name, "max_uV", + constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } -- cgit v0.10.2 From 1d7372e15ebd7f56a336fabe6ee31f8e692cd9cb Mon Sep 17 00:00:00 2001 From: Daniel Walker Date: Wed, 17 Nov 2010 15:30:28 -0800 Subject: drivers: regulator: core: convert to using pr_ macros The regulator framework uses a lot of printks with a specific formatting using __func__. This converts them to use pr_ calls with a central format string. Cc: bleong@codeaurora.org Signed-off-by: Daniel Walker Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 7c09063..8d492f4 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -13,7 +13,7 @@ * */ -#define pr_fmt(fmt) "%s:" fmt, __func__ +#define pr_fmt(fmt) "%s: " fmt, __func__ #include #include @@ -116,13 +116,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev, BUG_ON(*min_uV > *max_uV); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } @@ -144,13 +142,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, BUG_ON(*min_uA > *max_uA); if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } @@ -179,18 +175,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) } if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } if (!(rdev->constraints->valid_modes_mask & mode)) { - printk(KERN_ERR "%s: invalid mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + pr_err("invalid mode %x for %s\n", mode, rdev_get_name(rdev)); return -EINVAL; } return 0; @@ -200,13 +193,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) static int regulator_check_drms(struct regulator_dev *rdev) { if (!rdev->constraints) { - printk(KERN_ERR "%s: no constraints for %s\n", __func__, - rdev_get_name(rdev)); + pr_err("no constraints for %s\n", rdev_get_name(rdev)); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - printk(KERN_ERR "%s: operation not allowed for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); return -EPERM; } return 0; @@ -603,20 +594,18 @@ static int suspend_set_state(struct regulator_dev *rdev, */ if (!rstate->enabled && !rstate->disabled) { if (can_set_state) - printk(KERN_WARNING "%s: No configuration for %s\n", - __func__, rdev_get_name(rdev)); + pr_warning("No configuration for %s\n", + rdev_get_name(rdev)); return 0; } if (rstate->enabled && rstate->disabled) { - printk(KERN_ERR "%s: invalid configuration for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid configuration for %s\n", rdev_get_name(rdev)); return -EINVAL; } if (!can_set_state) { - printk(KERN_ERR "%s: no way to set suspend state\n", - __func__); + pr_err("no way to set suspend state\n"); return -EINVAL; } @@ -625,15 +614,14 @@ static int suspend_set_state(struct regulator_dev *rdev, else ret = rdev->desc->ops->set_suspend_disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enabled/disable\n", __func__); + pr_err("failed to enabled/disable\n"); return ret; } if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); if (ret < 0) { - printk(KERN_ERR "%s: failed to set voltage\n", - __func__); + pr_err("failed to set voltage\n"); return ret; } } @@ -641,7 +629,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set mode\n", __func__); + pr_err("failed to set mode\n"); return ret; } } @@ -739,9 +727,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV, &selector); if (ret < 0) { - printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n", - __func__, - rdev->constraints->min_uV, name); + pr_err("failed to apply %duV constraint to %s\n", + rdev->constraints->min_uV, name); rdev->constraints = NULL; return ret; } @@ -848,8 +835,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_state) { ret = suspend_prepare(rdev, constraints->initial_state); if (ret < 0) { - printk(KERN_ERR "%s: failed to set suspend state for %s\n", - __func__, name); + pr_err("failed to set suspend state for %s\n", + name); rdev->constraints = NULL; goto out; } @@ -857,17 +844,16 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_mode) { if (!ops->set_mode) { - printk(KERN_ERR "%s: no set_mode operation for %s\n", - __func__, name); + pr_err("no set_mode operation for %s\n", + name); ret = -EINVAL; goto out; } ret = ops->set_mode(rdev, constraints->initial_mode); if (ret < 0) { - printk(KERN_ERR - "%s: failed to set initial mode for %s: %d\n", - __func__, name, ret); + pr_err("failed to set initial mode for %s: %d\n", + name, ret); goto out; } } @@ -878,8 +864,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, if ((constraints->always_on || constraints->boot_on) && ops->enable) { ret = ops->enable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s\n", - __func__, name); + pr_err("failed to enable %s\n", name); rdev->constraints = NULL; goto out; } @@ -907,9 +892,8 @@ static int set_supply(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, "supply"); if (err) { - printk(KERN_ERR - "%s: could not add device link %s err %d\n", - __func__, supply_rdev->dev.kobj.name, err); + pr_err("could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); goto out; } rdev->supply = supply_rdev; @@ -1039,8 +1023,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->dev_attr.show = device_requested_uA_show; err = device_create_file(dev, ®ulator->dev_attr); if (err < 0) { - printk(KERN_WARNING "%s: could not add regulator_dev" - " load sysfs\n", __func__); + pr_warning("could not add regulator_dev" + " requested microamps sysfs entry\n"); goto attr_name_err; } @@ -1057,9 +1041,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { - printk(KERN_WARNING - "%s: could not add device link %s err %d\n", - __func__, dev->kobj.name, err); + pr_warning("could not add device link %s err %d\n", + dev->kobj.name, err); goto link_name_err; } } @@ -1096,7 +1079,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int ret; if (id == NULL) { - printk(KERN_ERR "regulator: get() with no identifier\n"); + pr_err("regulator: get() with no identifier\n"); return regulator; } @@ -1282,8 +1265,8 @@ static int _regulator_enable(struct regulator_dev *rdev) ret = _regulator_enable(rdev->supply); mutex_unlock(&rdev->supply->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); + pr_err("failed to enable %s: %d\n", + rdev_get_name(rdev), ret); return ret; } } @@ -1310,10 +1293,9 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret >= 0) { delay = ret; } else { - printk(KERN_WARNING - "%s: enable_time() failed for %s: %d\n", - __func__, rdev_get_name(rdev), - ret); + pr_warning("enable_time() failed for %s: %d\n", + rdev_get_name(rdev), + ret); delay = 0; } @@ -1338,8 +1320,8 @@ static int _regulator_enable(struct regulator_dev *rdev) trace_regulator_enable_complete(rdev_get_name(rdev)); } else if (ret < 0) { - printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", - __func__, rdev_get_name(rdev), ret); + pr_err("is_enabled() failed for %s: %d\n", + rdev_get_name(rdev), ret); return ret; } /* Fallthrough on positive return values - already enabled */ @@ -1396,8 +1378,8 @@ static int _regulator_disable(struct regulator_dev *rdev, ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to disable %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to disable %s\n", + rdev_get_name(rdev)); return ret; } @@ -1469,8 +1451,8 @@ static int _regulator_force_disable(struct regulator_dev *rdev, /* ah well, who wants to live forever... */ ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - printk(KERN_ERR "%s: failed to force disable %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to force disable %s\n", + rdev_get_name(rdev)); return ret; } /* notify other consumers that power has been forced off */ @@ -1911,8 +1893,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) /* get output voltage */ output_uV = rdev->desc->ops->get_voltage(rdev); if (output_uV <= 0) { - printk(KERN_ERR "%s: invalid output voltage found for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid output voltage found for %s\n", + rdev_get_name(rdev)); goto out; } @@ -1922,8 +1904,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) else input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { - printk(KERN_ERR "%s: invalid input voltage found for %s\n", - __func__, rdev_get_name(rdev)); + pr_err("invalid input voltage found for %s\n", + rdev_get_name(rdev)); goto out; } @@ -1936,16 +1918,16 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) total_uA_load); ret = regulator_check_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to get optimum mode for %s @" - " %d uA %d -> %d uV\n", __func__, rdev_get_name(rdev), + pr_err("failed to get optimum mode for %s @" + " %d uA %d -> %d uV\n", rdev_get_name(rdev), total_uA_load, input_uV, output_uV); goto out; } ret = rdev->desc->ops->set_mode(rdev, mode); if (ret < 0) { - printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", - __func__, mode, rdev_get_name(rdev)); + pr_err("failed to set optimum mode %x for %s\n", + mode, rdev_get_name(rdev)); goto out; } ret = mode; @@ -2494,8 +2476,7 @@ int regulator_suspend_prepare(suspend_state_t state) mutex_unlock(&rdev->mutex); if (ret < 0) { - printk(KERN_ERR "%s: failed to prepare %s\n", - __func__, rdev_get_name(rdev)); + pr_err("failed to prepare %s\n", rdev_get_name(rdev)); goto out; } } @@ -2653,13 +2634,10 @@ static int __init regulator_init_complete(void) if (has_full_constraints) { /* We log since this may kill the system if it * goes wrong. */ - printk(KERN_INFO "%s: disabling %s\n", - __func__, name); + pr_info("disabling %s\n", name); ret = ops->disable(rdev); if (ret != 0) { - printk(KERN_ERR - "%s: couldn't disable %s: %d\n", - __func__, name, ret); + pr_err("couldn't disable %s: %d\n", name, ret); } } else { /* The intention is that in future we will @@ -2667,9 +2645,8 @@ static int __init regulator_init_complete(void) * so warn even if we aren't going to do * anything here. */ - printk(KERN_WARNING - "%s: incomplete constraints, leaving %s on\n", - __func__, name); + pr_warning("incomplete constraints, leaving %s on\n", + name); } unlock: -- cgit v0.10.2 From 4c35508fc0b7883820923b3b8eb9fea25d35cf72 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Nov 2010 13:51:18 +0000 Subject: regulator: Fix obfuscated log messages Don't use %s to format fixed static strings into log messages, it just makes searching for and reading the message in the kernel source needlessly hard. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 8d492f4..fe47860 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -760,7 +760,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("%s '%s' voltage constraints\n", "invalid", + pr_err("invalid '%s' voltage constraints\n", name); return -EINVAL; } @@ -782,22 +782,20 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("%s '%s' voltage constraints\n", "unsupportable", + pr_err("unsupportable '%s' voltage constraints\n", name); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("override '%s' %s, %d -> %d\n", - name, "min_uV", - constraints->min_uV, min_uV); + pr_debug("override '%s' min_uV, %d -> %d\n", + name, constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("override '%s' %s, %d -> %d\n", - name, "max_uV", - constraints->max_uV, max_uV); + pr_debug("override '%s' max_uV, %d -> %d\n", + name, constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } -- cgit v0.10.2 From 50ba5ca4be30674517ca33425648ec43d93f9a69 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 22 Nov 2010 13:51:19 +0000 Subject: regulator: Remove regulator core version announcement The version hasn't been updated since the regulator API was merged in 2.6.27 so just remove it - now we're in mainline the kernel version is much more useful. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index fe47860..64a56a7 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -32,8 +32,6 @@ #include "dummy.h" -#define REGULATOR_VERSION "0.5" - static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); @@ -2580,8 +2578,6 @@ static int __init regulator_init(void) { int ret; - printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION); - ret = class_register(®ulator_class); regulator_dummy_init(); -- cgit v0.10.2 From f4d6adf11b0a596ac4fee2fb2591f286de35c088 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 19 Nov 2010 12:07:44 +0000 Subject: regulator: Fix prototype for MAX8998 buck set_voltage() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index cb28cf8..7568df6 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -354,7 +354,7 @@ static inline void buck2_gpio_set(int gpio, int v) } static int max8998_set_voltage_buck(struct regulator_dev *rdev, - int min_uV, int max_uV, int *selector) + int min_uV, int max_uV, unsigned *selector) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); struct max8998_platform_data *pdata = -- cgit v0.10.2 From f8c12fe329c8da9f50d8b2b1183eeaa4d587e747 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Nov 2010 15:55:17 +0000 Subject: regulator: Copy constraints from regulators when initialising them Currently the regulator API uses the constraints structure passed in to the core throughout the lifetime of the object. This means that it is not possible to mark the constraints as __initdata so if the kernel supports many boards the constraints for all of them are kept around throughout the lifetime of the system, consuming memory needlessly. By copying constraints that are actually used we allow the use of __initdata, saving memory when multiple boards are supported. This also means the constraints can be const. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 64a56a7..40cf7b9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -813,23 +813,26 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, * set_mode. */ static int set_machine_constraints(struct regulator_dev *rdev, - struct regulation_constraints *constraints) + const struct regulation_constraints *constraints) { int ret = 0; const char *name; struct regulator_ops *ops = rdev->desc->ops; - rdev->constraints = constraints; + rdev->constraints = kmemdup(constraints, sizeof(*constraints), + GFP_KERNEL); + if (!rdev->constraints) + return -ENOMEM; name = rdev_get_name(rdev); - ret = machine_constraints_voltage(rdev, constraints); + ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) goto out; /* do we need to setup our suspend state */ if (constraints->initial_state) { - ret = suspend_prepare(rdev, constraints->initial_state); + ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { pr_err("failed to set suspend state for %s\n", name); @@ -846,7 +849,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, goto out; } - ret = ops->set_mode(rdev, constraints->initial_mode); + ret = ops->set_mode(rdev, rdev->constraints->initial_mode); if (ret < 0) { pr_err("failed to set initial mode for %s: %d\n", name, ret); @@ -857,7 +860,8 @@ static int set_machine_constraints(struct regulator_dev *rdev, /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ - if ((constraints->always_on || constraints->boot_on) && ops->enable) { + if ((rdev->constraints->always_on || rdev->constraints->boot_on) && + ops->enable) { ret = ops->enable(rdev); if (ret < 0) { pr_err("failed to enable %s\n", name); @@ -2289,7 +2293,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) * Returns 0 on success. */ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, + struct device *dev, const struct regulator_init_data *init_data, void *driver_data) { static atomic_t regulator_no = ATOMIC_INIT(0); @@ -2444,6 +2448,7 @@ void regulator_unregister(struct regulator_dev *rdev) if (rdev->supply) sysfs_remove_link(&rdev->dev.kobj, "supply"); device_unregister(&rdev->dev); + kfree(rdev->constraints); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4275cd4..cce5753 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -192,7 +192,7 @@ struct regulator_dev { }; struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, - struct device *dev, struct regulator_init_data *init_data, + struct device *dev, const struct regulator_init_data *init_data, void *driver_data); void regulator_unregister(struct regulator_dev *rdev); -- cgit v0.10.2 From 6220b87bfd60d77bf9b19e18aa093110b0f34d41 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 29 Nov 2010 15:57:48 +0000 Subject: regulator: Remove duplicate consts from mc13873 driver voltage tables They're not needed and sparse is verbosely upset about them. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 47ea999..e99917a 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -100,78 +100,78 @@ struct mc13783_regulator { }; /* Voltage Values */ -static const int const mc13783_sw3_val[] = { +static const int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, }; -static const int const mc13783_vaudio_val[] = { +static const int mc13783_vaudio_val[] = { 2775000, }; -static const int const mc13783_viohi_val[] = { +static const int mc13783_viohi_val[] = { 2775000, }; -static const int const mc13783_violo_val[] = { +static const int mc13783_violo_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vdig_val[] = { +static const int mc13783_vdig_val[] = { 1200000, 1300000, 1500000, 1800000, }; -static const int const mc13783_vgen_val[] = { +static const int mc13783_vgen_val[] = { 1200000, 1300000, 1500000, 1800000, 1100000, 2000000, 2775000, 2400000, }; -static const int const mc13783_vrfdig_val[] = { +static const int mc13783_vrfdig_val[] = { 1200000, 1500000, 1800000, 1875000, }; -static const int const mc13783_vrfref_val[] = { +static const int mc13783_vrfref_val[] = { 2475000, 2600000, 2700000, 2775000, }; -static const int const mc13783_vrfcp_val[] = { +static const int mc13783_vrfcp_val[] = { 2700000, 2775000, }; -static const int const mc13783_vsim_val[] = { +static const int mc13783_vsim_val[] = { 1800000, 2900000, 3000000, }; -static const int const mc13783_vesim_val[] = { +static const int mc13783_vesim_val[] = { 1800000, 2900000, }; -static const int const mc13783_vcam_val[] = { +static const int mc13783_vcam_val[] = { 1500000, 1800000, 2500000, 2550000, 2600000, 2750000, 2800000, 3000000, }; -static const int const mc13783_vrfbg_val[] = { +static const int mc13783_vrfbg_val[] = { 1250000, }; -static const int const mc13783_vvib_val[] = { +static const int mc13783_vvib_val[] = { 1300000, 1800000, 2000000, 3000000, }; -static const int const mc13783_vmmc_val[] = { +static const int mc13783_vmmc_val[] = { 1600000, 1800000, 2000000, 2600000, 2700000, 2800000, 2900000, 3000000, }; -static const int const mc13783_vrf_val[] = { +static const int mc13783_vrf_val[] = { 1500000, 1875000, 2700000, 2775000, }; -static const int const mc13783_gpo_val[] = { +static const int mc13783_gpo_val[] = { 3100000, }; -static const int const mc13783_pwgtdrv_val[] = { +static const int mc13783_pwgtdrv_val[] = { 5500000, }; -- cgit v0.10.2 From 5da84fd99bb1ab1c7cd39d0cf7c08bb63931a59a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Tue, 30 Nov 2010 05:53:48 -0800 Subject: regulator: Add and use rdev_ macros On Tue, 2010-11-30 at 10:52 +0000, Mark Brown wrote: > On Mon, Nov 29, 2010 at 05:12:56PM -0800, Joe Perches wrote: > > Just to please broonie... > > Signed-off-by: Joe Perches > As usual when fixing review issues please revise your original patch > rather than posting a fresh patch. Here's an earlier comment: On Thu, 2010-11-18 at 13:30 +0000, Mark Brown wrote: > This looks reasonable, please rebase on top of Daniel's patches and > submit it properly (with changelog and so on). Sometimes it's simpler for an upstream maintainer to do something like: git am -s patch -p1 < patch2.mbox git commit --amend file instead of back and forthing. Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 40cf7b9..e63366f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -32,6 +32,15 @@ #include "dummy.h" +#define rdev_err(rdev, fmt, ...) \ + pr_err("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_warn(rdev, fmt, ...) \ + pr_warn("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_info(rdev, fmt, ...) \ + pr_info("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) +#define rdev_dbg(rdev, fmt, ...) \ + pr_debug("%s: " fmt, rdev_get_name(rdev), ##__VA_ARGS__) + static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); @@ -114,11 +123,11 @@ static int regulator_check_voltage(struct regulator_dev *rdev, BUG_ON(*min_uV > *max_uV); if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -140,11 +149,11 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, BUG_ON(*min_uA > *max_uA); if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_CURRENT)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } @@ -173,15 +182,15 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) } if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_MODE)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } if (!(rdev->constraints->valid_modes_mask & mode)) { - pr_err("invalid mode %x for %s\n", mode, rdev_get_name(rdev)); + rdev_err(rdev, "invalid mode %x\n", mode); return -EINVAL; } return 0; @@ -191,11 +200,11 @@ static int regulator_check_mode(struct regulator_dev *rdev, int mode) static int regulator_check_drms(struct regulator_dev *rdev) { if (!rdev->constraints) { - pr_err("no constraints for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "no constraints\n"); return -ENODEV; } if (!(rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) { - pr_err("operation not allowed for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "operation not allowed\n"); return -EPERM; } return 0; @@ -592,18 +601,17 @@ static int suspend_set_state(struct regulator_dev *rdev, */ if (!rstate->enabled && !rstate->disabled) { if (can_set_state) - pr_warning("No configuration for %s\n", - rdev_get_name(rdev)); + rdev_warn(rdev, "No configuration\n"); return 0; } if (rstate->enabled && rstate->disabled) { - pr_err("invalid configuration for %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "invalid configuration\n"); return -EINVAL; } if (!can_set_state) { - pr_err("no way to set suspend state\n"); + rdev_err(rdev, "no way to set suspend state\n"); return -EINVAL; } @@ -612,14 +620,14 @@ static int suspend_set_state(struct regulator_dev *rdev, else ret = rdev->desc->ops->set_suspend_disable(rdev); if (ret < 0) { - pr_err("failed to enabled/disable\n"); + rdev_err(rdev, "failed to enabled/disable\n"); return ret; } if (rdev->desc->ops->set_suspend_voltage && rstate->uV > 0) { ret = rdev->desc->ops->set_suspend_voltage(rdev, rstate->uV); if (ret < 0) { - pr_err("failed to set voltage\n"); + rdev_err(rdev, "failed to set voltage\n"); return ret; } } @@ -627,7 +635,7 @@ static int suspend_set_state(struct regulator_dev *rdev, if (rdev->desc->ops->set_suspend_mode && rstate->mode > 0) { ret = rdev->desc->ops->set_suspend_mode(rdev, rstate->mode); if (ret < 0) { - pr_err("failed to set mode\n"); + rdev_err(rdev, "failed to set mode\n"); return ret; } } @@ -705,14 +713,13 @@ static void print_constraints(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += sprintf(buf + count, "standby"); - printk(KERN_INFO "regulator: %s: %s\n", rdev_get_name(rdev), buf); + rdev_info(rdev, "regulator: %s\n", buf); } static int machine_constraints_voltage(struct regulator_dev *rdev, struct regulation_constraints *constraints) { struct regulator_ops *ops = rdev->desc->ops; - const char *name = rdev_get_name(rdev); int ret; unsigned selector; @@ -725,8 +732,8 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, rdev->constraints->max_uV, &selector); if (ret < 0) { - pr_err("failed to apply %duV constraint to %s\n", - rdev->constraints->min_uV, name); + rdev_err(rdev, "failed to apply %duV constraint\n", + rdev->constraints->min_uV); rdev->constraints = NULL; return ret; } @@ -758,8 +765,7 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* else require explicit machine-level constraints */ if (cmin <= 0 || cmax <= 0 || cmax < cmin) { - pr_err("invalid '%s' voltage constraints\n", - name); + rdev_err(rdev, "invalid voltage constraints\n"); return -EINVAL; } @@ -780,20 +786,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, /* final: [min_uV..max_uV] valid iff constraints valid */ if (max_uV < min_uV) { - pr_err("unsupportable '%s' voltage constraints\n", - name); + rdev_err(rdev, "unsupportable voltage constraints\n"); return -EINVAL; } /* use regulator's subset of machine constraints */ if (constraints->min_uV < min_uV) { - pr_debug("override '%s' min_uV, %d -> %d\n", - name, constraints->min_uV, min_uV); + rdev_dbg(rdev, "override min_uV, %d -> %d\n", + constraints->min_uV, min_uV); constraints->min_uV = min_uV; } if (constraints->max_uV > max_uV) { - pr_debug("override '%s' max_uV, %d -> %d\n", - name, constraints->max_uV, max_uV); + rdev_dbg(rdev, "override max_uV, %d -> %d\n", + constraints->max_uV, max_uV); constraints->max_uV = max_uV; } } @@ -816,7 +821,6 @@ static int set_machine_constraints(struct regulator_dev *rdev, const struct regulation_constraints *constraints) { int ret = 0; - const char *name; struct regulator_ops *ops = rdev->desc->ops; rdev->constraints = kmemdup(constraints, sizeof(*constraints), @@ -824,8 +828,6 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (!rdev->constraints) return -ENOMEM; - name = rdev_get_name(rdev); - ret = machine_constraints_voltage(rdev, rdev->constraints); if (ret != 0) goto out; @@ -834,8 +836,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_state) { ret = suspend_prepare(rdev, rdev->constraints->initial_state); if (ret < 0) { - pr_err("failed to set suspend state for %s\n", - name); + rdev_err(rdev, "failed to set suspend state\n"); rdev->constraints = NULL; goto out; } @@ -843,16 +844,14 @@ static int set_machine_constraints(struct regulator_dev *rdev, if (constraints->initial_mode) { if (!ops->set_mode) { - pr_err("no set_mode operation for %s\n", - name); + rdev_err(rdev, "no set_mode operation\n"); ret = -EINVAL; goto out; } ret = ops->set_mode(rdev, rdev->constraints->initial_mode); if (ret < 0) { - pr_err("failed to set initial mode for %s: %d\n", - name, ret); + rdev_err(rdev, "failed to set initial mode: %d\n", ret); goto out; } } @@ -864,7 +863,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, ops->enable) { ret = ops->enable(rdev); if (ret < 0) { - pr_err("failed to enable %s\n", name); + rdev_err(rdev, "failed to enable\n"); rdev->constraints = NULL; goto out; } @@ -892,8 +891,8 @@ static int set_supply(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj, "supply"); if (err) { - pr_err("could not add device link %s err %d\n", - supply_rdev->dev.kobj.name, err); + rdev_err(rdev, "could not add device link %s err %d\n", + supply_rdev->dev.kobj.name, err); goto out; } rdev->supply = supply_rdev; @@ -949,10 +948,10 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, continue; dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n", - dev_name(&node->regulator->dev), - node->regulator->desc->name, - supply, - dev_name(&rdev->dev), rdev_get_name(rdev)); + dev_name(&node->regulator->dev), + node->regulator->desc->name, + supply, + dev_name(&rdev->dev), rdev_get_name(rdev)); return -EBUSY; } @@ -1023,8 +1022,7 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, regulator->dev_attr.show = device_requested_uA_show; err = device_create_file(dev, ®ulator->dev_attr); if (err < 0) { - pr_warning("could not add regulator_dev" - " requested microamps sysfs entry\n"); + rdev_warn(rdev, "could not add regulator_dev requested microamps sysfs entry\n"); goto attr_name_err; } @@ -1041,8 +1039,8 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, err = sysfs_create_link(&rdev->dev.kobj, &dev->kobj, buf); if (err) { - pr_warning("could not add device link %s err %d\n", - dev->kobj.name, err); + rdev_warn(rdev, "could not add device link %s err %d\n", + dev->kobj.name, err); goto link_name_err; } } @@ -1079,7 +1077,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, int ret; if (id == NULL) { - pr_err("regulator: get() with no identifier\n"); + pr_err("get() with no identifier\n"); return regulator; } @@ -1113,8 +1111,8 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, * substitute in a dummy regulator so consumers can continue. */ if (!has_full_constraints) { - pr_warning("%s supply %s not found, using dummy regulator\n", - devname, id); + pr_warn("%s supply %s not found, using dummy regulator\n", + devname, id); rdev = dummy_regulator_rdev; goto found; } @@ -1265,8 +1263,7 @@ static int _regulator_enable(struct regulator_dev *rdev) ret = _regulator_enable(rdev->supply); mutex_unlock(&rdev->supply->mutex); if (ret < 0) { - pr_err("failed to enable %s: %d\n", - rdev_get_name(rdev), ret); + rdev_err(rdev, "failed to enable: %d\n", ret); return ret; } } @@ -1293,8 +1290,7 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret >= 0) { delay = ret; } else { - pr_warning("enable_time() failed for %s: %d\n", - rdev_get_name(rdev), + rdev_warn(rdev, "enable_time() failed: %d\n", ret); delay = 0; } @@ -1320,8 +1316,7 @@ static int _regulator_enable(struct regulator_dev *rdev) trace_regulator_enable_complete(rdev_get_name(rdev)); } else if (ret < 0) { - pr_err("is_enabled() failed for %s: %d\n", - rdev_get_name(rdev), ret); + rdev_err(rdev, "is_enabled() failed: %d\n", ret); return ret; } /* Fallthrough on positive return values - already enabled */ @@ -1378,8 +1373,7 @@ static int _regulator_disable(struct regulator_dev *rdev, ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - pr_err("failed to disable %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "failed to disable\n"); return ret; } @@ -1451,8 +1445,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev, /* ah well, who wants to live forever... */ ret = rdev->desc->ops->disable(rdev); if (ret < 0) { - pr_err("failed to force disable %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "failed to force disable\n"); return ret; } /* notify other consumers that power has been forced off */ @@ -1893,8 +1886,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) /* get output voltage */ output_uV = rdev->desc->ops->get_voltage(rdev); if (output_uV <= 0) { - pr_err("invalid output voltage found for %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "invalid output voltage found\n"); goto out; } @@ -1904,8 +1896,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) else input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { - pr_err("invalid input voltage found for %s\n", - rdev_get_name(rdev)); + rdev_err(rdev, "invalid input voltage found\n"); goto out; } @@ -1918,16 +1909,14 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) total_uA_load); ret = regulator_check_mode(rdev, mode); if (ret < 0) { - pr_err("failed to get optimum mode for %s @" - " %d uA %d -> %d uV\n", rdev_get_name(rdev), - total_uA_load, input_uV, output_uV); + rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n", + total_uA_load, input_uV, output_uV); goto out; } ret = rdev->desc->ops->set_mode(rdev, mode); if (ret < 0) { - pr_err("failed to set optimum mode %x for %s\n", - mode, rdev_get_name(rdev)); + rdev_err(rdev, "failed to set optimum mode %x\n", mode); goto out; } ret = mode; @@ -2058,7 +2047,7 @@ int regulator_bulk_enable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to enable %s: %d\n", consumers[i].supply, ret); + pr_err("Failed to enable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_disable(consumers[i].consumer); @@ -2093,8 +2082,7 @@ int regulator_bulk_disable(int num_consumers, return 0; err: - printk(KERN_ERR "Failed to disable %s: %d\n", consumers[i].supply, - ret); + pr_err("Failed to disable %s: %d\n", consumers[i].supply, ret); for (--i; i >= 0; --i) regulator_enable(consumers[i].consumer); @@ -2477,7 +2465,7 @@ int regulator_suspend_prepare(suspend_state_t state) mutex_unlock(&rdev->mutex); if (ret < 0) { - pr_err("failed to prepare %s\n", rdev_get_name(rdev)); + rdev_err(rdev, "failed to prepare\n"); goto out; } } @@ -2599,7 +2587,6 @@ static int __init regulator_init_complete(void) struct regulator_ops *ops; struct regulation_constraints *c; int enabled, ret; - const char *name; mutex_lock(®ulator_list_mutex); @@ -2611,8 +2598,6 @@ static int __init regulator_init_complete(void) ops = rdev->desc->ops; c = rdev->constraints; - name = rdev_get_name(rdev); - if (!ops->disable || (c && c->always_on)) continue; @@ -2633,10 +2618,10 @@ static int __init regulator_init_complete(void) if (has_full_constraints) { /* We log since this may kill the system if it * goes wrong. */ - pr_info("disabling %s\n", name); + rdev_info(rdev, "disabling\n"); ret = ops->disable(rdev); if (ret != 0) { - pr_err("couldn't disable %s: %d\n", name, ret); + rdev_err(rdev, "couldn't disable: %d\n", ret); } } else { /* The intention is that in future we will @@ -2644,8 +2629,7 @@ static int __init regulator_init_complete(void) * so warn even if we aren't going to do * anything here. */ - pr_warning("incomplete constraints, leaving %s on\n", - name); + rdev_warn(rdev, "incomplete constraints, leaving on\n"); } unlock: -- cgit v0.10.2 From 05fda3b1abc23d832144e9497fb218870927d645 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Fri, 3 Dec 2010 11:31:07 +0100 Subject: regulator: Take into account the requirements of all consumers Extend the regulator_set_voltage() function to take into account the voltage requirements of all consumers of the regulator being changed, in order to set the voltage to the minimum voltage acceptable to all consumers. The existing behaviour was that the latest regulator_set_voltage() call would win over previous regulator_set_voltage() calls even if setting the voltage to a non-acceptable level from other consumers. Signed-off-by: Thomas Petazzoni Cc: Liam Girdwood Cc: Mark Brown Cc: Kevin Hilman Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e63366f..a1b1237 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -142,6 +142,27 @@ static int regulator_check_voltage(struct regulator_dev *rdev, return 0; } +/* Make sure we select a voltage that suits the needs of all + * regulator consumers + */ +static int regulator_check_consumers(struct regulator_dev *rdev, + int *min_uV, int *max_uV) +{ + struct regulator *regulator; + + list_for_each_entry(regulator, &rdev->consumer_list, list) { + if (*max_uV > regulator->max_uV) + *max_uV = regulator->max_uV; + if (*min_uV < regulator->min_uV) + *min_uV = regulator->min_uV; + } + + if (*min_uV > *max_uV) + return -EINVAL; + + return 0; +} + /* current constraint check */ static int regulator_check_current_limit(struct regulator_dev *rdev, int *min_uA, int *max_uA) @@ -1637,6 +1658,10 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) regulator->min_uV = min_uV; regulator->max_uV = max_uV; + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); -- cgit v0.10.2 From 43e7ee33f2a8d20238267b789791386739247478 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 6 Dec 2010 14:05:19 -0800 Subject: drivers/regulator: Update WARN uses Align arguments. Signed-off-by: Joe Perches Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a1b1237..5d07e5d 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1379,8 +1379,7 @@ static int _regulator_disable(struct regulator_dev *rdev, *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, - "unbalanced disables for %s\n", - rdev_get_name(rdev))) + "unbalanced disables for %s\n", rdev_get_name(rdev))) return -EIO; /* are we the last user and permitted to disable ? */ -- cgit v0.10.2 From 1bf5a1f86a328122714680cd59951074b4f31e07 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:06 +0000 Subject: regulator: Use _regulator_get_voltage() consistently Rather than referencing the get_voltage() operation directly in the ops struct use the internal _regulator_get_voltage() API call to do so, facilitating refactoring. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 5d07e5d..671eb53 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -581,14 +581,15 @@ static void drms_uA_update(struct regulator_dev *rdev) return; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) return; /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) return; @@ -1908,16 +1909,17 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) goto out; /* get output voltage */ - output_uV = rdev->desc->ops->get_voltage(rdev); + output_uV = _regulator_get_voltage(rdev); if (output_uV <= 0) { rdev_err(rdev, "invalid output voltage found\n"); goto out; } /* get input voltage */ - if (rdev->supply && rdev->supply->desc->ops->get_voltage) - input_uV = rdev->supply->desc->ops->get_voltage(rdev->supply); - else + input_uV = 0; + if (rdev->supply) + input_uV = _regulator_get_voltage(rdev->supply); + if (input_uV <= 0) input_uV = rdev->constraints->input_uV; if (input_uV <= 0) { rdev_err(rdev, "invalid input voltage found\n"); -- cgit v0.10.2 From 476c2d83c7ffb2429b2a504fbdb4326fc8a9d0e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:07 +0000 Subject: regulator: Allow drivers to report voltages as selectors Since drivers already have to provide an API for translating selectors into voltages they may as well just report the selector values directly to the core API rather than implement the lookup themselves. The old interface is left in place for now, but may be removed in future. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 671eb53..b362dbd 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -577,7 +577,9 @@ static void drms_uA_update(struct regulator_dev *rdev) err = regulator_check_drms(rdev); if (err < 0 || !rdev->desc->ops->get_optimum_mode || - !rdev->desc->ops->get_voltage || !rdev->desc->ops->set_mode) + (!rdev->desc->ops->get_voltage && + !rdev->desc->ops->get_voltage_sel) || + !rdev->desc->ops->set_mode) return; /* get output voltage */ @@ -1682,7 +1684,14 @@ EXPORT_SYMBOL_GPL(regulator_set_voltage); static int _regulator_get_voltage(struct regulator_dev *rdev) { - /* sanity check */ + int sel; + + if (rdev->desc->ops->get_voltage_sel) { + sel = rdev->desc->ops->get_voltage_sel(rdev); + if (sel < 0) + return sel; + return rdev->desc->ops->list_voltage(rdev, sel); + } if (rdev->desc->ops->get_voltage) return rdev->desc->ops->get_voltage(rdev); else @@ -2191,7 +2200,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) int status = 0; /* some attributes need specific methods to be displayed */ - if (ops->get_voltage) { + if (ops->get_voltage || ops->get_voltage_sel) { status = device_create_file(dev, &dev_attr_microvolts); if (status < 0) return status; @@ -2327,6 +2336,16 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (!init_data) return ERR_PTR(-EINVAL); + /* Only one of each should be implemented */ + WARN_ON(regulator_desc->ops->get_voltage && + regulator_desc->ops->get_voltage_sel); + + /* If we're using selectors we must implement list_voltage. */ + if (regulator_desc->ops->get_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } + rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) return ERR_PTR(-ENOMEM); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index cce5753..bf3e653 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -43,6 +43,8 @@ enum regulator_status { * @set_voltage: Set the voltage for the regulator within the range specified. * The driver should select the voltage closest to min_uV. * @get_voltage: Return the currently configured voltage for the regulator. + * @get_voltage_sel: Return the currently configured voltage selector for the + * regulator. * @list_voltage: Return one of the supported voltages, in microvolts; zero * if the selector indicates a voltage that is unusable on this system; * or negative errno. Selectors range from zero to one less than @@ -82,6 +84,7 @@ struct regulator_ops { int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector); int (*get_voltage) (struct regulator_dev *); + int (*get_voltage_sel) (struct regulator_dev *); /* get/set regulator current */ int (*set_current_limit) (struct regulator_dev *, -- cgit v0.10.2 From afb8bb805bb9336ec1f7b74e7b5c0e9baceb42c1 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 10 Dec 2010 17:28:08 +0000 Subject: regulator: Convert WM831x drivers to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/wm831x-dcdc.c b/drivers/regulator/wm831x-dcdc.c index 71da6b2..8b0d2c4 100644 --- a/drivers/regulator/wm831x-dcdc.c +++ b/drivers/regulator/wm831x-dcdc.c @@ -377,14 +377,14 @@ static int wm831x_buckv_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_set_bits(wm831x, reg, WM831X_DC1_SLP_VSEL_MASK, vsel); } -static int wm831x_buckv_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckv_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); if (dcdc->dvs_gpio && dcdc->dvs_gpio_state) - return wm831x_buckv_list_voltage(rdev, dcdc->dvs_vsel); + return dcdc->dvs_vsel; else - return wm831x_buckv_list_voltage(rdev, dcdc->on_vsel); + return dcdc->on_vsel; } /* Current limit options */ @@ -426,7 +426,7 @@ static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev) static struct regulator_ops wm831x_buckv_ops = { .set_voltage = wm831x_buckv_set_voltage, - .get_voltage = wm831x_buckv_get_voltage, + .get_voltage_sel = wm831x_buckv_get_voltage_sel, .list_voltage = wm831x_buckv_list_voltage, .set_suspend_voltage = wm831x_buckv_set_suspend_voltage, .set_current_limit = wm831x_buckv_set_current_limit, @@ -678,7 +678,7 @@ static int wm831x_buckp_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_buckp_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) +static int wm831x_buckp_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_dcdc *dcdc = rdev_get_drvdata(rdev); struct wm831x *wm831x = dcdc->wm831x; @@ -689,12 +689,12 @@ static int wm831x_buckp_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - return wm831x_buckp_list_voltage(rdev, val & WM831X_DC3_ON_VSEL_MASK); + return val & WM831X_DC3_ON_VSEL_MASK; } static struct regulator_ops wm831x_buckp_ops = { .set_voltage = wm831x_buckp_set_voltage, - .get_voltage = wm831x_buckp_get_voltage, + .get_voltage_sel = wm831x_buckp_get_voltage_sel, .list_voltage = wm831x_buckp_list_voltage, .set_suspend_voltage = wm831x_buckp_set_suspend_voltage, diff --git a/drivers/regulator/wm831x-ldo.c b/drivers/regulator/wm831x-ldo.c index 9594e71..c94fc5b 100644 --- a/drivers/regulator/wm831x-ldo.c +++ b/drivers/regulator/wm831x-ldo.c @@ -160,7 +160,7 @@ static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_gp_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_gp_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -173,7 +173,7 @@ static int wm831x_gp_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO1_ON_VSEL_MASK; - return wm831x_gp_ldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev) @@ -293,7 +293,7 @@ static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev, static struct regulator_ops wm831x_gp_ldo_ops = { .list_voltage = wm831x_gp_ldo_list_voltage, - .get_voltage = wm831x_gp_ldo_get_voltage, + .get_voltage_sel = wm831x_gp_ldo_get_voltage_sel, .set_voltage = wm831x_gp_ldo_set_voltage, .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage, .get_mode = wm831x_gp_ldo_get_mode, @@ -465,7 +465,7 @@ static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_aldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_aldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -478,7 +478,7 @@ static int wm831x_aldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO7_ON_VSEL_MASK; - return wm831x_aldo_list_voltage(rdev, ret); + return ret; } static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev) @@ -559,7 +559,7 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_aldo_ops = { .list_voltage = wm831x_aldo_list_voltage, - .get_voltage = wm831x_aldo_get_voltage, + .get_voltage_sel = wm831x_aldo_get_voltage_sel, .set_voltage = wm831x_aldo_set_voltage, .set_suspend_voltage = wm831x_aldo_set_suspend_voltage, .get_mode = wm831x_aldo_get_mode, @@ -718,7 +718,7 @@ static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev, return wm831x_alive_ldo_set_voltage_int(rdev, reg, uV, uV, &selector); } -static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) +static int wm831x_alive_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm831x_ldo *ldo = rdev_get_drvdata(rdev); struct wm831x *wm831x = ldo->wm831x; @@ -731,7 +731,7 @@ static int wm831x_alive_ldo_get_voltage(struct regulator_dev *rdev) ret &= WM831X_LDO11_ON_VSEL_MASK; - return wm831x_alive_ldo_list_voltage(rdev, ret); + return ret; } static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) @@ -753,7 +753,7 @@ static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev) static struct regulator_ops wm831x_alive_ldo_ops = { .list_voltage = wm831x_alive_ldo_list_voltage, - .get_voltage = wm831x_alive_ldo_get_voltage, + .get_voltage_sel = wm831x_alive_ldo_get_voltage_sel, .set_voltage = wm831x_alive_ldo_set_voltage, .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage, .get_status = wm831x_alive_ldo_get_status, -- cgit v0.10.2 From 1394fd2826afb2adf7f6c4833d36a0feba22e665 Mon Sep 17 00:00:00 2001 From: Cyril Chemparathy Date: Tue, 7 Dec 2010 12:04:11 -0500 Subject: regulator: add driver for tps6524x regulator TPS6524X provides three step-down converters and two general-purpose LDO voltage regulators. This device is interfaced using SPI. Signed-off-by: Cyril Chemparathy Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index dd30e88..da34981 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -250,5 +250,15 @@ config REGULATOR_TPS6586X help This driver supports TPS6586X voltage regulator chips. +config REGULATOR_TPS6524X + tristate "TI TPS6524X Power regulators" + depends on SPI + help + This driver supports TPS6524X voltage regulator chips. TPS6524X + provides three step-down converters and two general-purpose LDO + voltage regulators. This device is interfaced using a customized + serial interface currently supported on the sequencer serial + port controller. + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index bff8157..cf71df7 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o +obj-$(CONFIG_REGULATOR_TPS6524X) += tps6524x-regulator.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o diff --git a/drivers/regulator/tps6524x-regulator.c b/drivers/regulator/tps6524x-regulator.c new file mode 100644 index 0000000..176a6be --- /dev/null +++ b/drivers/regulator/tps6524x-regulator.c @@ -0,0 +1,693 @@ +/* + * Regulator driver for TPS6524x PMIC + * + * Copyright (C) 2010 Texas Instruments + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, + * whether express or implied; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_LDO_SET 0x0 +#define LDO_ILIM_MASK 1 /* 0 = 400-800, 1 = 900-1500 */ +#define LDO_VSEL_MASK 0x0f +#define LDO2_ILIM_SHIFT 12 +#define LDO2_VSEL_SHIFT 4 +#define LDO1_ILIM_SHIFT 8 +#define LDO1_VSEL_SHIFT 0 + +#define REG_BLOCK_EN 0x1 +#define BLOCK_MASK 1 +#define BLOCK_LDO1_SHIFT 0 +#define BLOCK_LDO2_SHIFT 1 +#define BLOCK_LCD_SHIFT 2 +#define BLOCK_USB_SHIFT 3 + +#define REG_DCDC_SET 0x2 +#define DCDC_VDCDC_MASK 0x1f +#define DCDC_VDCDC1_SHIFT 0 +#define DCDC_VDCDC2_SHIFT 5 +#define DCDC_VDCDC3_SHIFT 10 + +#define REG_DCDC_EN 0x3 +#define DCDCDCDC_EN_MASK 0x1 +#define DCDCDCDC1_EN_SHIFT 0 +#define DCDCDCDC1_PG_MSK BIT(1) +#define DCDCDCDC2_EN_SHIFT 2 +#define DCDCDCDC2_PG_MSK BIT(3) +#define DCDCDCDC3_EN_SHIFT 4 +#define DCDCDCDC3_PG_MSK BIT(5) + +#define REG_USB 0x4 +#define USB_ILIM_SHIFT 0 +#define USB_ILIM_MASK 0x3 +#define USB_TSD_SHIFT 2 +#define USB_TSD_MASK 0x3 +#define USB_TWARN_SHIFT 4 +#define USB_TWARN_MASK 0x3 +#define USB_IWARN_SD BIT(6) +#define USB_FAST_LOOP BIT(7) + +#define REG_ALARM 0x5 +#define ALARM_LDO1 BIT(0) +#define ALARM_DCDC1 BIT(1) +#define ALARM_DCDC2 BIT(2) +#define ALARM_DCDC3 BIT(3) +#define ALARM_LDO2 BIT(4) +#define ALARM_USB_WARN BIT(5) +#define ALARM_USB_ALARM BIT(6) +#define ALARM_LCD BIT(9) +#define ALARM_TEMP_WARM BIT(10) +#define ALARM_TEMP_HOT BIT(11) +#define ALARM_NRST BIT(14) +#define ALARM_POWERUP BIT(15) + +#define REG_INT_ENABLE 0x6 +#define INT_LDO1 BIT(0) +#define INT_DCDC1 BIT(1) +#define INT_DCDC2 BIT(2) +#define INT_DCDC3 BIT(3) +#define INT_LDO2 BIT(4) +#define INT_USB_WARN BIT(5) +#define INT_USB_ALARM BIT(6) +#define INT_LCD BIT(9) +#define INT_TEMP_WARM BIT(10) +#define INT_TEMP_HOT BIT(11) +#define INT_GLOBAL_EN BIT(15) + +#define REG_INT_STATUS 0x7 +#define STATUS_LDO1 BIT(0) +#define STATUS_DCDC1 BIT(1) +#define STATUS_DCDC2 BIT(2) +#define STATUS_DCDC3 BIT(3) +#define STATUS_LDO2 BIT(4) +#define STATUS_USB_WARN BIT(5) +#define STATUS_USB_ALARM BIT(6) +#define STATUS_LCD BIT(9) +#define STATUS_TEMP_WARM BIT(10) +#define STATUS_TEMP_HOT BIT(11) + +#define REG_SOFTWARE_RESET 0xb +#define REG_WRITE_ENABLE 0xd +#define REG_REV_ID 0xf + +#define N_DCDC 3 +#define N_LDO 2 +#define N_SWITCH 2 +#define N_REGULATORS (3 /* DCDC */ + \ + 2 /* LDO */ + \ + 2 /* switch */) + +#define FIXED_ILIMSEL BIT(0) +#define FIXED_VOLTAGE BIT(1) + +#define CMD_READ(reg) ((reg) << 6) +#define CMD_WRITE(reg) (BIT(5) | (reg) << 6) +#define STAT_CLK BIT(3) +#define STAT_WRITE BIT(2) +#define STAT_INVALID BIT(1) +#define STAT_WP BIT(0) + +struct field { + int reg; + int shift; + int mask; +}; + +struct supply_info { + const char *name; + int n_voltages; + const int *voltages; + int fixed_voltage; + int n_ilimsels; + const int *ilimsels; + int fixed_ilimsel; + int flags; + struct field enable, voltage, ilimsel; +}; + +struct tps6524x { + struct device *dev; + struct spi_device *spi; + struct mutex lock; + struct regulator_desc desc[N_REGULATORS]; + struct regulator_dev *rdev[N_REGULATORS]; +}; + +static int __read_reg(struct tps6524x *hw, int reg) +{ + int error = 0; + u16 cmd = CMD_READ(reg), in; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = ∈ + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "read reg %d, data %x, status %x\n", + reg, in, status); + + if (!(status & STAT_CLK) || (status & STAT_WRITE)) + return -EIO; + + if (status & STAT_INVALID) + return -EINVAL; + + return in; +} + +static int read_reg(struct tps6524x *hw, int reg) +{ + int ret; + + mutex_lock(&hw->lock); + ret = __read_reg(hw, reg); + mutex_unlock(&hw->lock); + + return ret; +} + +static int __write_reg(struct tps6524x *hw, int reg, int val) +{ + int error = 0; + u16 cmd = CMD_WRITE(reg), out = val; + u8 status; + struct spi_message m; + struct spi_transfer t[3]; + + spi_message_init(&m); + memset(t, 0, sizeof(t)); + + t[0].tx_buf = &cmd; + t[0].len = 2; + t[0].bits_per_word = 12; + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = &out; + t[1].len = 2; + t[1].bits_per_word = 16; + spi_message_add_tail(&t[1], &m); + + t[2].rx_buf = &status; + t[2].len = 1; + t[2].bits_per_word = 4; + spi_message_add_tail(&t[2], &m); + + error = spi_sync(hw->spi, &m); + if (error < 0) + return error; + + dev_dbg(hw->dev, "wrote reg %d, data %x, status %x\n", + reg, out, status); + + if (!(status & STAT_CLK) || !(status & STAT_WRITE)) + return -EIO; + + if (status & (STAT_INVALID | STAT_WP)) + return -EINVAL; + + return error; +} + +static int __rmw_reg(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + ret = __read_reg(hw, reg); + if (ret < 0) + return ret; + + ret &= ~mask; + ret |= val; + + ret = __write_reg(hw, reg, ret); + + return (ret < 0) ? ret : 0; +} + +static int rmw_protect(struct tps6524x *hw, int reg, int mask, int val) +{ + int ret; + + mutex_lock(&hw->lock); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 1); + if (ret) { + dev_err(hw->dev, "failed to set write enable\n"); + goto error; + } + + ret = __rmw_reg(hw, reg, mask, val); + if (ret) + dev_err(hw->dev, "failed to rmw register %d\n", reg); + + ret = __write_reg(hw, REG_WRITE_ENABLE, 0); + if (ret) { + dev_err(hw->dev, "failed to clear write enable\n"); + goto error; + } + +error: + mutex_unlock(&hw->lock); + + return ret; +} + +static int read_field(struct tps6524x *hw, const struct field *field) +{ + int tmp; + + tmp = read_reg(hw, field->reg); + if (tmp < 0) + return tmp; + + return (tmp >> field->shift) & field->mask; +} + +static int write_field(struct tps6524x *hw, const struct field *field, + int val) +{ + if (val & ~field->mask) + return -EOVERFLOW; + + return rmw_protect(hw, field->reg, + field->mask << field->shift, + val << field->shift); +} + +static const int dcdc1_voltages[] = { + 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, + 1000000, 1025000, 1050000, 1075000, + 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, + 1300000, 1325000, 1350000, 1375000, + 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, +}; + +static const int dcdc2_voltages[] = { + 1400000, 1450000, 1500000, 1550000, + 1600000, 1650000, 1700000, 1750000, + 1800000, 1850000, 1900000, 1950000, + 2000000, 2050000, 2100000, 2150000, + 2200000, 2250000, 2300000, 2350000, + 2400000, 2450000, 2500000, 2550000, + 2600000, 2650000, 2700000, 2750000, + 2800000, 2850000, 2900000, 2950000, +}; + +static const int dcdc3_voltages[] = { + 2400000, 2450000, 2500000, 2550000, 2600000, + 2650000, 2700000, 2750000, 2800000, 2850000, + 2900000, 2950000, 3000000, 3050000, 3100000, + 3150000, 3200000, 3250000, 3300000, 3350000, + 3400000, 3450000, 3500000, 3550000, 3600000, +}; + +static const int ldo1_voltages[] = { + 4300000, 4350000, 4400000, 4450000, + 4500000, 4550000, 4600000, 4650000, + 4700000, 4750000, 4800000, 4850000, + 4900000, 4950000, 5000000, 5050000, +}; + +static const int ldo2_voltages[] = { + 1100000, 1150000, 1200000, 1250000, + 1300000, 1700000, 1750000, 1800000, + 1850000, 1900000, 3150000, 3200000, + 3250000, 3300000, 3350000, 3400000, +}; + +static const int ldo_ilimsel[] = { + 400000, 1500000 +}; + +static const int usb_ilimsel[] = { + 200000, 400000, 800000, 1000000 +}; + +#define __MK_FIELD(_reg, _mask, _shift) \ + { .reg = (_reg), .mask = (_mask), .shift = (_shift), } + +static const struct supply_info supply_info[N_REGULATORS] = { + { + .name = "DCDC1", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc1_voltages), + .voltages = dcdc1_voltages, + .fixed_ilimsel = 2400000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC1_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC1_SHIFT), + }, + { + .name = "DCDC2", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc2_voltages), + .voltages = dcdc2_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC2_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC2_SHIFT), + }, + { + .name = "DCDC3", + .flags = FIXED_ILIMSEL, + .n_voltages = ARRAY_SIZE(dcdc3_voltages), + .voltages = dcdc3_voltages, + .fixed_ilimsel = 1200000, + .enable = __MK_FIELD(REG_DCDC_EN, DCDCDCDC_EN_MASK, + DCDCDCDC3_EN_SHIFT), + .voltage = __MK_FIELD(REG_DCDC_SET, DCDC_VDCDC_MASK, + DCDC_VDCDC3_SHIFT), + }, + { + .name = "LDO1", + .n_voltages = ARRAY_SIZE(ldo1_voltages), + .voltages = ldo1_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO1_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO1_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO1_ILIM_SHIFT), + }, + { + .name = "LDO2", + .n_voltages = ARRAY_SIZE(ldo2_voltages), + .voltages = ldo2_voltages, + .n_ilimsels = ARRAY_SIZE(ldo_ilimsel), + .ilimsels = ldo_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LDO2_SHIFT), + .voltage = __MK_FIELD(REG_LDO_SET, LDO_VSEL_MASK, + LDO2_VSEL_SHIFT), + .ilimsel = __MK_FIELD(REG_LDO_SET, LDO_ILIM_MASK, + LDO2_ILIM_SHIFT), + }, + { + .name = "USB", + .flags = FIXED_VOLTAGE, + .fixed_voltage = 5000000, + .n_ilimsels = ARRAY_SIZE(usb_ilimsel), + .ilimsels = usb_ilimsel, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_USB_SHIFT), + .ilimsel = __MK_FIELD(REG_USB, USB_ILIM_MASK, + USB_ILIM_SHIFT), + }, + { + .name = "LCD", + .flags = FIXED_VOLTAGE | FIXED_ILIMSEL, + .fixed_voltage = 5000000, + .fixed_ilimsel = 400000, + .enable = __MK_FIELD(REG_BLOCK_EN, BLOCK_MASK, + BLOCK_LCD_SHIFT), + }, +}; + +static int list_voltage(struct regulator_dev *rdev, unsigned selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return selector ? -EINVAL : info->fixed_voltage; + + return ((selector < info->n_voltages) ? + info->voltages[selector] : -EINVAL); +} + +static int set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) +{ + const struct supply_info *info; + struct tps6524x *hw; + unsigned i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return -EINVAL; + + for (i = 0; i < info->n_voltages; i++) + if (min_uV <= info->voltages[i] && + max_uV >= info->voltages[i]) + break; + + if (i >= info->n_voltages) + i = info->n_voltages - 1; + + *selector = info->voltages[i]; + + return write_field(hw, &info->voltage, i); +} + +static int get_voltage(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_VOLTAGE) + return info->fixed_voltage; + + ret = read_field(hw, &info->voltage); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_voltages)) + return -EIO; + + return info->voltages[ret]; +} + +static int set_current_limit(struct regulator_dev *rdev, int min_uA, + int max_uA) +{ + const struct supply_info *info; + struct tps6524x *hw; + int i; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return -EINVAL; + + for (i = 0; i < info->n_ilimsels; i++) + if (min_uA <= info->ilimsels[i] && + max_uA >= info->ilimsels[i]) + break; + + if (i >= info->n_ilimsels) + return -EINVAL; + + return write_field(hw, &info->ilimsel, i); +} + +static int get_current_limit(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + int ret; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + if (info->flags & FIXED_ILIMSEL) + return info->fixed_ilimsel; + + ret = read_field(hw, &info->ilimsel); + if (ret < 0) + return ret; + if (WARN_ON(ret >= info->n_ilimsels)) + return -EIO; + + return info->ilimsels[ret]; +} + +static int enable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 1); +} + +static int disable_supply(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return write_field(hw, &info->enable, 0); +} + +static int is_supply_enabled(struct regulator_dev *rdev) +{ + const struct supply_info *info; + struct tps6524x *hw; + + hw = rdev_get_drvdata(rdev); + info = &supply_info[rdev_get_id(rdev)]; + + return read_field(hw, &info->enable); +} + +static struct regulator_ops regulator_ops = { + .is_enabled = is_supply_enabled, + .enable = enable_supply, + .disable = disable_supply, + .get_voltage = get_voltage, + .set_voltage = set_voltage, + .list_voltage = list_voltage, + .set_current_limit = set_current_limit, + .get_current_limit = get_current_limit, +}; + +static int __devexit pmic_remove(struct spi_device *spi) +{ + struct tps6524x *hw = spi_get_drvdata(spi); + int i; + + if (!hw) + return 0; + for (i = 0; i < N_REGULATORS; i++) { + if (hw->rdev[i]) + regulator_unregister(hw->rdev[i]); + hw->rdev[i] = NULL; + } + spi_set_drvdata(spi, NULL); + kfree(hw); + return 0; +} + +static int __devinit pmic_probe(struct spi_device *spi) +{ + struct tps6524x *hw; + struct device *dev = &spi->dev; + const struct supply_info *info = supply_info; + struct regulator_init_data *init_data; + int ret = 0, i; + + init_data = dev->platform_data; + if (!init_data) { + dev_err(dev, "could not find regulator platform data\n"); + return -EINVAL; + } + + hw = kzalloc(sizeof(struct tps6524x), GFP_KERNEL); + if (!hw) { + dev_err(dev, "cannot allocate regulator private data\n"); + return -ENOMEM; + } + spi_set_drvdata(spi, hw); + + memset(hw, 0, sizeof(struct tps6524x)); + hw->dev = dev; + hw->spi = spi_dev_get(spi); + mutex_init(&hw->lock); + + for (i = 0; i < N_REGULATORS; i++, info++, init_data++) { + hw->desc[i].name = info->name; + hw->desc[i].id = i; + hw->desc[i].n_voltages = info->n_voltages; + hw->desc[i].ops = ®ulator_ops; + hw->desc[i].type = REGULATOR_VOLTAGE; + hw->desc[i].owner = THIS_MODULE; + + if (info->flags & FIXED_VOLTAGE) + hw->desc[i].n_voltages = 1; + + hw->rdev[i] = regulator_register(&hw->desc[i], dev, + init_data, hw); + if (IS_ERR(hw->rdev[i])) { + ret = PTR_ERR(hw->rdev[i]); + hw->rdev[i] = NULL; + goto fail; + } + } + + return 0; + +fail: + pmic_remove(spi); + return ret; +} + +static struct spi_driver pmic_driver = { + .probe = pmic_probe, + .remove = __devexit_p(pmic_remove), + .driver = { + .name = "tps6524x", + .owner = THIS_MODULE, + }, +}; + +static int __init pmic_driver_init(void) +{ + return spi_register_driver(&pmic_driver); +} +module_init(pmic_driver_init); + +static void __exit pmic_driver_exit(void) +{ + spi_unregister_driver(&pmic_driver); +} +module_exit(pmic_driver_exit); + +MODULE_DESCRIPTION("TPS6524X PMIC Driver"); +MODULE_AUTHOR("Cyril Chemparathy"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:tps6524x"); -- cgit v0.10.2 From cb189b07d57b574cc14382e2130960b0a0193c23 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:40 +0100 Subject: regulators: Moved define for number of regulators in ab8500 The define for number of regulators is moved from ab8500-core to ab8500-regulator so that the regulator driver can be updated independently of ab8500-core. This also changes the platform configuration structure of ab8500-core so that it contains a pointer to the regulator_init_data array plus number of regulators instead of an fixed size array of pointers to regulator_init_data. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 2f4ec0f..5670775 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -370,6 +370,12 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } pdata = dev_get_platdata(ab8500->dev); + /* make sure the platform data has the correct size */ + if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { + dev_err(&pdev->dev, "platform configuration error\n"); + return -EINVAL; + } + /* register all regulators */ for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; @@ -380,7 +386,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) info->ab8500 = ab8500; info->regulator = regulator_register(&info->desc, &pdev->dev, - pdata->regulator[i], info); + &pdata->regulator[i], info); if (IS_ERR(info->regulator)) { err = PTR_ERR(info->regulator); dev_err(&pdev->dev, "failed to register regulator %s\n", diff --git a/include/linux/mfd/ab8500.h b/include/linux/mfd/ab8500.h index d63b605..85cf2c2 100644 --- a/include/linux/mfd/ab8500.h +++ b/include/linux/mfd/ab8500.h @@ -99,8 +99,6 @@ #define AB8500_NR_IRQS 104 #define AB8500_NUM_IRQ_REGS 13 -#define AB8500_NUM_REGULATORS 15 - /** * struct ab8500 - ab8500 internal structure * @dev: parent device @@ -145,7 +143,8 @@ struct regulator_init_data; struct ab8500_platform_data { int irq_base; void (*init) (struct ab8500 *); - struct regulator_init_data *regulator[AB8500_NUM_REGULATORS]; + int num_regulator; + struct regulator_init_data *regulator; }; extern int __devinit ab8500_init(struct ab8500 *ab8500); diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h index f509877..6a210f1 100644 --- a/include/linux/regulator/ab8500.h +++ b/include/linux/regulator/ab8500.h @@ -11,15 +11,17 @@ #define __LINUX_MFD_AB8500_REGULATOR_H /* AB8500 regulators */ -#define AB8500_LDO_AUX1 0 -#define AB8500_LDO_AUX2 1 -#define AB8500_LDO_AUX3 2 -#define AB8500_LDO_INTCORE 3 -#define AB8500_LDO_TVOUT 4 -#define AB8500_LDO_AUDIO 5 -#define AB8500_LDO_ANAMIC1 6 -#define AB8500_LDO_ANAMIC2 7 -#define AB8500_LDO_DMIC 8 -#define AB8500_LDO_ANA 9 - +enum ab8500_regulator_id { + AB8500_LDO_AUX1, + AB8500_LDO_AUX2, + AB8500_LDO_AUX3, + AB8500_LDO_INTCORE, + AB8500_LDO_TVOUT, + AB8500_LDO_AUDIO, + AB8500_LDO_ANAMIC1, + AB8500_LDO_ANAMIC2, + AB8500_LDO_DMIC, + AB8500_LDO_ANA, + AB8500_NUM_REGULATORS, +}; #endif -- cgit v0.10.2 From 65e03ed2d0cd49259c527e488b94e93fcf23f62e Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:41 +0100 Subject: regulators: Fixed errors in ab8500 register mapping For INTCORE and TVOUT regulators, the low power register bit is included in the mask so that enable will set the regulator in normal (high power) mode. ANAMIC1, ANAMIC2, DMIC regulator settings are swapped with each other so that the correct regulator gets enabled/disabled. ANA regulator register address is corrected. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 5670775..4efe3cf 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -330,19 +330,19 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38, + AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* * Fixed Voltage LDOs * name, o/p uV, ctrl bank, ctrl reg, enable, disable */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x2), AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), + AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), }; static inline struct ab8500_regulator_info *find_regulator_info(int id) -- cgit v0.10.2 From deaca1ee8250e204cab6ca9390e43ac63b46959c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:42 +0100 Subject: regulators: Clean out unused code in ab8500 regulators The find_regulator function was unused so it has been removed. The ab8500 pointer in the regulator info structure was unused and so it has also been removed. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 4efe3cf..51ff569 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -29,7 +29,6 @@ /** * struct ab8500_regulator_info - ab8500 regulator information * @desc: regulator description - * @ab8500: ab8500 parent * @regulator_dev: regulator device * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) @@ -47,7 +46,6 @@ struct ab8500_regulator_info { struct device *dev; struct regulator_desc desc; - struct ab8500 *ab8500; struct regulator_dev *regulator; int max_uV; int min_uV; @@ -345,19 +343,6 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), }; -static inline struct ab8500_regulator_info *find_regulator_info(int id) -{ - struct ab8500_regulator_info *info; - int i; - - for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { - info = &ab8500_regulator_info[i]; - if (info->desc.id == id) - return info; - } - return NULL; -} - static __devinit int ab8500_regulator_probe(struct platform_device *pdev) { struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent); @@ -383,7 +368,6 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) /* assign per-regulator data */ info = &ab8500_regulator_info[i]; info->dev = &pdev->dev; - info->ab8500 = ab8500; info->regulator = regulator_register(&info->desc, &pdev->dev, &pdata->regulator[i], info); -- cgit v0.10.2 From 2b75151a1041f200ee3f36475ba389da43664bb4 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:43 +0100 Subject: regulators: Added ab8500 v2 support The AUX3 regulator voltage setting is changed in ab8500 v2 compared to ab8500 v1. This patch adds v2 support while keeping support for v1. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 51ff569..9a3dc79 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -81,6 +81,17 @@ static const int ldo_vauxn_voltages[] = { 3300000, }; +static const int ldo_vaux3_voltages[] = { + 1200000, + 1500000, + 1800000, + 2100000, + 2500000, + 2750000, + 2790000, + 2910000, +}; + static const int ldo_vintcore_voltages[] = { 1200000, 1225000, @@ -326,8 +337,8 @@ static struct ab8500_regulator_info ab8500_regulator_info[] = { ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0x7, + ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), @@ -369,6 +380,19 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) info = &ab8500_regulator_info[i]; info->dev = &pdev->dev; + /* fix for hardware before ab8500v2.0 */ + if (abx500_get_chip_id(info->dev) < 0x20) { + if (info->desc.id == AB8500_LDO_AUX3) { + info->desc.n_voltages = + ARRAY_SIZE(ldo_vauxn_voltages); + info->supported_voltages = ldo_vauxn_voltages; + info->voltages_len = + ARRAY_SIZE(ldo_vauxn_voltages); + info->voltage_mask = 0xf; + } + } + + /* register regulator with framework */ info->regulator = regulator_register(&info->desc, &pdev->dev, &pdata->regulator[i], info); if (IS_ERR(info->regulator)) { -- cgit v0.10.2 From e1159e6d9ac5faf42abedd2fc02234e3d946585a Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:44 +0100 Subject: regulators: Updated ab8500 variable names, macro names and comments The regulator enumeration is used for putting the regulator data in correct place in the info array. This should be matched in the board configuration. Variable names are updated to be more consistent, comments are corrected and macros have been edited to be consistent. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 9a3dc79..ccb0bfd 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -3,18 +3,13 @@ * * License Terms: GNU General Public License v2 * - * Author: Sundar Iyer for ST-Ericsson + * Authors: Sundar Iyer for ST-Ericsson + * Bengt Jonsson for ST-Ericsson * * AB8500 peripheral regulators * - * AB8500 supports the following regulators, - * LDOs - VAUDIO, VANAMIC2/2, VDIGMIC, VINTCORE12, VTVOUT, - * VAUX1/2/3, VANA - * - * for DB8500 cut 1.0 and previous versions of the silicon, all accesses - * to registers are through the DB8500 SPI. In cut 1.1 onwards, these - * accesses are through the DB8500 PRCMU I2C - * + * AB8500 supports the following regulators: + * VAUX1/2/3, VINTCORE, VTVOUT, VAUDIO, VAMIC1/2, VDMIC, VANA */ #include #include @@ -28,6 +23,7 @@ /** * struct ab8500_regulator_info - ab8500 regulator information + * @dev: device pointer * @desc: regulator description * @regulator_dev: regulator device * @max_uV: maximum voltage (for variable voltage supplies) @@ -35,12 +31,12 @@ * @fixed_uV: typical voltage (for fixed voltage supplies) * @update_bank: bank to control on/off * @update_reg: register to control on/off - * @mask: mask to enable/disable regulator - * @enable: bits to enable the regulator in normal(high power) mode + * @update_mask: mask to enable/disable regulator + * @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 * @voltage_mask: mask to control regulator voltage - * @supported_voltages: supported voltage table + * @voltages: supported voltage table * @voltages_len: number of supported voltages for the regulator */ struct ab8500_regulator_info { @@ -52,12 +48,12 @@ struct ab8500_regulator_info { int fixed_uV; u8 update_bank; u8 update_reg; - u8 mask; - u8 enable; + u8 update_mask; + u8 update_val_enable; u8 voltage_bank; u8 voltage_reg; u8 voltage_mask; - int const *supported_voltages; + int const *voltages; int voltages_len; }; @@ -112,7 +108,8 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) return -EINVAL; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, info->enable); + info->update_bank, info->update_reg, + info->update_mask, info->update_val_enable); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); @@ -129,7 +126,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) return -EINVAL; ret = abx500_mask_and_set_register_interruptible(info->dev, - info->update_bank, info->update_reg, info->mask, 0x0); + info->update_bank, info->update_reg, + info->update_mask, 0x0); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); @@ -154,7 +152,7 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) return ret; } - if (value & info->mask) + if (value & info->update_mask) return true; else return false; @@ -176,7 +174,7 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) if (selector >= info->voltages_len) return -EINVAL; - return info->supported_voltages[selector]; + return info->voltages[selector]; } static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) @@ -200,9 +198,9 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) /* vintcore has a different layout */ value &= info->voltage_mask; if (regulator_id == AB8500_LDO_INTCORE) - ret = info->supported_voltages[value >> 0x3]; + ret = info->voltages[value >> 0x3]; else - ret = info->supported_voltages[value]; + ret = info->voltages[value]; return ret; } @@ -215,8 +213,8 @@ static int ab8500_get_best_voltage_index(struct regulator_dev *rdev, /* check the supported voltage */ for (i = 0; i < info->voltages_len; i++) { - if ((info->supported_voltages[i] >= min_uV) && - (info->supported_voltages[i] <= max_uV)) + if ((info->voltages[i] >= min_uV) && + (info->voltages[i] <= max_uV)) return i; } @@ -284,74 +282,79 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \ - reg_enable, volt_bank, volt_reg, volt_mask, \ - voltages, len_volts) \ -{ \ +#define AB8500_LDO(_id, _min_mV, _max_mV, \ + _u_bank, _u_reg, _u_mask, _u_val_enable, \ + _v_bank, _v_reg, _v_mask, _v_table, _v_table_len) \ +[AB8500_LDO_##_id] = { \ .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ + .name = "LDO-" #_id, \ + .ops = &ab8500_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = AB8500_LDO_##_id, \ + .owner = THIS_MODULE, \ }, \ - .min_uV = (min) * 1000, \ - .max_uV = (max) * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ - .voltage_bank = volt_bank, \ - .voltage_reg = volt_reg, \ - .voltage_mask = volt_mask, \ - .supported_voltages = voltages, \ - .voltages_len = len_volts, \ - .fixed_uV = 0, \ + .min_uV = (_min_mV) * 1000, \ + .max_uV = (_max_mV) * 1000, \ + .update_bank = _u_bank, \ + .update_reg = _u_reg, \ + .update_mask = _u_mask, \ + .update_val_enable = _u_val_enable, \ + .voltage_bank = _v_bank, \ + .voltage_reg = _v_reg, \ + .voltage_mask = _v_mask, \ + .voltages = _v_table, \ + .voltages_len = _v_table_len, \ + .fixed_uV = 0, \ } -#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \ - reg_mask, reg_enable) \ -{ \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_ldo_fixed_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .fixed_uV = fixed * 1000, \ - .update_bank = bank, \ - .update_reg = reg, \ - .mask = reg_mask, \ - .enable = reg_enable, \ +#define AB8500_FIXED_LDO(_id, _fixed_mV, \ + _u_bank, _u_reg, _u_mask, _u_val_enable) \ +[AB8500_LDO_##_id] = { \ + .desc = { \ + .name = "LDO-" #_id, \ + .ops = &ab8500_ldo_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = AB8500_LDO_##_id, \ + .owner = THIS_MODULE, \ + }, \ + .fixed_uV = (_fixed_mV) * 1000, \ + .update_bank = _u_bank, \ + .update_reg = _u_reg, \ + .update_mask = _u_mask, \ + .update_val_enable = _u_val_enable, \ } static struct ab8500_regulator_info ab8500_regulator_info[] = { /* - * Variable Voltage LDOs - * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask, - * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table, - * num supported volts + * Variable Voltage Regulators + * name, min mV, max mV, + * update bank, reg, mask, enable val + * volt bank, reg, mask, table, table length */ - AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0x7, - ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x44, 0x4, 0x03, 0x80, 0x38, + AB8500_LDO(AUX1, 1100, 3300, + 0x04, 0x09, 0x03, 0x01, 0x04, 0x1f, 0x0f, + ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX2, 1100, 3300, + 0x04, 0x09, 0x0c, 0x04, 0x04, 0x20, 0x0f, + ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), + AB8500_LDO(AUX3, 1100, 3300, + 0x04, 0x0a, 0x03, 0x01, 0x04, 0x21, 0x07, + ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), + AB8500_LDO(INTCORE, 1100, 3300, + 0x03, 0x80, 0x44, 0x04, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* - * Fixed Voltage LDOs - * name, o/p uV, ctrl bank, ctrl reg, enable, disable + * Fixed Voltage Regulators + * name, fixed mV, + * update bank, reg, mask, enable val */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x2), - AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), - AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0xc, 0x4), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x02), + AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x02, 0x02), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), + AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0x0c, 0x04), }; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) @@ -385,7 +388,7 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) if (info->desc.id == AB8500_LDO_AUX3) { info->desc.n_voltages = ARRAY_SIZE(ldo_vauxn_voltages); - info->supported_voltages = ldo_vauxn_voltages; + info->voltages = ldo_vauxn_voltages; info->voltages_len = ARRAY_SIZE(ldo_vauxn_voltages); info->voltage_mask = 0xf; -- cgit v0.10.2 From fc24b426fff45ddaf5663a11daa31ba74f6b6b4f Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:45 +0100 Subject: regulators: Modified ab8500 error handling Error handling is updated to catch NULL pointer errors. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index ccb0bfd..2a15b63 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -100,12 +100,13 @@ static const int ldo_vintcore_voltages[] = { static int ab8500_regulator_enable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, @@ -118,12 +119,13 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) static int ab8500_regulator_disable(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_mask_and_set_register_interruptible(info->dev, info->update_bank, info->update_reg, @@ -136,13 +138,14 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 value; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + 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, &value); @@ -160,12 +163,12 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* return the uV for the fixed regulators */ if (info->fixed_uV) @@ -179,13 +182,14 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); u8 value; - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, info->voltage_reg, &value); @@ -197,7 +201,7 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) /* vintcore has a different layout */ value &= info->voltage_mask; - if (regulator_id == AB8500_LDO_INTCORE) + if (info->desc.id == AB8500_LDO_INTCORE) ret = info->voltages[value >> 0x3]; else ret = info->voltages[value]; @@ -225,12 +229,13 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { - int regulator_id, ret; + int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } /* get the appropriate voltages within the range */ ret = ab8500_get_best_voltage_index(rdev, min_uV, max_uV); @@ -264,12 +269,12 @@ static struct regulator_ops ab8500_regulator_ops = { static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) { - int regulator_id; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - regulator_id = rdev_get_id(rdev); - if (regulator_id >= AB8500_NUM_REGULATORS) + if (info == NULL) { + dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); return -EINVAL; + } return info->fixed_uV; } @@ -368,6 +373,10 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) return -EINVAL; } pdata = dev_get_platdata(ab8500->dev); + if (!pdata) { + dev_err(&pdev->dev, "null pdata\n"); + return -EINVAL; + } /* make sure the platform data has the correct size */ if (pdata->num_regulator != ARRAY_SIZE(ab8500_regulator_info)) { -- cgit v0.10.2 From 09aefa12ac3c023e2db2315b0e229be98ef6bf23 Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:46 +0100 Subject: regulators: Added verbose debug messages to ab8500 regulators The verbose debug outputs register writes and reads that can be used to debug the driver. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 2a15b63..7d372b8 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -114,6 +114,12 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); + + 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); + return ret; } @@ -133,6 +139,12 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); + + 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, + info->update_mask, 0x0); + return ret; } @@ -140,7 +152,7 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -148,14 +160,20 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) } ret = abx500_get_register_interruptible(info->dev, - info->update_bank, info->update_reg, &value); + info->update_bank, info->update_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read 0x%x register\n", info->update_reg); return ret; } - if (value & info->update_mask) + dev_vdbg(rdev_get_dev(rdev), + "%s-is_enabled (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, regval); + + if (regval & info->update_mask) return true; else return false; @@ -182,29 +200,35 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int ret; + int ret, val; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); - u8 value; + 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->voltage_bank, - info->voltage_reg, &value); + ret = abx500_get_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, ®val); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); return ret; } + dev_vdbg(rdev_get_dev(rdev), + "%s-get_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); + /* vintcore has a different layout */ - value &= info->voltage_mask; + val = regval & info->voltage_mask; if (info->desc.id == AB8500_LDO_INTCORE) - ret = info->voltages[value >> 0x3]; + ret = info->voltages[val >> 0x3]; else - ret = info->voltages[value]; + ret = info->voltages[val]; return ret; } @@ -231,6 +255,7 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, { int ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 regval; if (info == NULL) { dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); @@ -248,13 +273,20 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, *selector = 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, (u8)ret); + 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"); + 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); + return ret; } @@ -418,6 +450,9 @@ static __devinit int ab8500_regulator_probe(struct platform_device *pdev) } return err; } + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-probed\n", info->desc.name); } return 0; @@ -430,6 +465,10 @@ static __devexit int ab8500_regulator_remove(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { struct ab8500_regulator_info *info = NULL; info = &ab8500_regulator_info[i]; + + dev_vdbg(rdev_get_dev(info->regulator), + "%s-remove\n", info->desc.name); + regulator_unregister(info->regulator); } -- cgit v0.10.2 From 6909b4522e0fc459d344fd42db444ca8b3106b8c Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:47 +0100 Subject: regulators: Removed macros for initialization of ab8500 regulators This patch removes the macros for initializing the regulators. The purpose is to remove one layer of abstraction and make the code easier to read. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 7d372b8..d9a052c 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -311,7 +311,7 @@ static int ab8500_fixed_get_voltage(struct regulator_dev *rdev) return info->fixed_uV; } -static struct regulator_ops ab8500_ldo_fixed_ops = { +static struct regulator_ops ab8500_regulator_fixed_ops = { .enable = ab8500_regulator_enable, .disable = ab8500_regulator_disable, .is_enabled = ab8500_regulator_is_enabled, @@ -319,79 +319,196 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, _min_mV, _max_mV, \ - _u_bank, _u_reg, _u_mask, _u_val_enable, \ - _v_bank, _v_reg, _v_mask, _v_table, _v_table_len) \ -[AB8500_LDO_##_id] = { \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .min_uV = (_min_mV) * 1000, \ - .max_uV = (_max_mV) * 1000, \ - .update_bank = _u_bank, \ - .update_reg = _u_reg, \ - .update_mask = _u_mask, \ - .update_val_enable = _u_val_enable, \ - .voltage_bank = _v_bank, \ - .voltage_reg = _v_reg, \ - .voltage_mask = _v_mask, \ - .voltages = _v_table, \ - .voltages_len = _v_table_len, \ - .fixed_uV = 0, \ -} - -#define AB8500_FIXED_LDO(_id, _fixed_mV, \ - _u_bank, _u_reg, _u_mask, _u_val_enable) \ -[AB8500_LDO_##_id] = { \ - .desc = { \ - .name = "LDO-" #_id, \ - .ops = &ab8500_ldo_fixed_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = AB8500_LDO_##_id, \ - .owner = THIS_MODULE, \ - }, \ - .fixed_uV = (_fixed_mV) * 1000, \ - .update_bank = _u_bank, \ - .update_reg = _u_reg, \ - .update_mask = _u_mask, \ - .update_val_enable = _u_val_enable, \ -} - -static struct ab8500_regulator_info ab8500_regulator_info[] = { +static struct ab8500_regulator_info + ab8500_regulator_info[AB8500_NUM_REGULATORS] = { /* * Variable Voltage Regulators * name, min mV, max mV, * update bank, reg, mask, enable val * volt bank, reg, mask, table, table length */ - AB8500_LDO(AUX1, 1100, 3300, - 0x04, 0x09, 0x03, 0x01, 0x04, 0x1f, 0x0f, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, - 0x04, 0x09, 0x0c, 0x04, 0x04, 0x20, 0x0f, - ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, - 0x04, 0x0a, 0x03, 0x01, 0x04, 0x21, 0x07, - ldo_vaux3_voltages, ARRAY_SIZE(ldo_vaux3_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, - 0x03, 0x80, 0x44, 0x04, 0x03, 0x80, 0x38, - ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), + [AB8500_LDO_AUX1] = { + .desc = { + .name = "LDO-AUX1", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX1, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x1f, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX2] = { + .desc = { + .name = "LDO-AUX2", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX2, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vauxn_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x09, + .update_mask = 0x0c, + .update_val_enable = 0x04, + .voltage_bank = 0x04, + .voltage_reg = 0x20, + .voltage_mask = 0x0f, + .voltages = ldo_vauxn_voltages, + .voltages_len = ARRAY_SIZE(ldo_vauxn_voltages), + }, + [AB8500_LDO_AUX3] = { + .desc = { + .name = "LDO-AUX3", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUX3, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vaux3_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x04, + .update_reg = 0x0a, + .update_mask = 0x03, + .update_val_enable = 0x01, + .voltage_bank = 0x04, + .voltage_reg = 0x21, + .voltage_mask = 0x07, + .voltages = ldo_vaux3_voltages, + .voltages_len = ARRAY_SIZE(ldo_vaux3_voltages), + }, + [AB8500_LDO_INTCORE] = { + .desc = { + .name = "LDO-INTCORE", + .ops = &ab8500_regulator_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_INTCORE, + .owner = THIS_MODULE, + .n_voltages = ARRAY_SIZE(ldo_vintcore_voltages), + }, + .min_uV = 1100000, + .max_uV = 3300000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x44, + .update_val_enable = 0x04, + .voltage_bank = 0x03, + .voltage_reg = 0x80, + .voltage_mask = 0x38, + .voltages = ldo_vintcore_voltages, + .voltages_len = ARRAY_SIZE(ldo_vintcore_voltages), + }, /* * Fixed Voltage Regulators * name, fixed mV, * update bank, reg, mask, enable val */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x82, 0x02), - AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x02, 0x02), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x08, 0x08), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x10, 0x10), - AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x04, 0x04), - AB8500_FIXED_LDO(ANA, 1200, 0x04, 0x06, 0x0c, 0x04), + [AB8500_LDO_TVOUT] = { + .desc = { + .name = "LDO-TVOUT", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_TVOUT, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x80, + .update_mask = 0x82, + .update_val_enable = 0x02, + }, + [AB8500_LDO_AUDIO] = { + .desc = { + .name = "LDO-AUDIO", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_AUDIO, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2000000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x02, + .update_val_enable = 0x02, + }, + [AB8500_LDO_ANAMIC1] = { + .desc = { + .name = "LDO-ANAMIC1", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC1, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x08, + .update_val_enable = 0x08, + }, + [AB8500_LDO_ANAMIC2] = { + .desc = { + .name = "LDO-ANAMIC2", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANAMIC2, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 2050000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x10, + .update_val_enable = 0x10, + }, + [AB8500_LDO_DMIC] = { + .desc = { + .name = "LDO-DMIC", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_DMIC, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1800000, + .update_bank = 0x03, + .update_reg = 0x83, + .update_mask = 0x04, + .update_val_enable = 0x04, + }, + [AB8500_LDO_ANA] = { + .desc = { + .name = "LDO-ANA", + .ops = &ab8500_regulator_fixed_ops, + .type = REGULATOR_VOLTAGE, + .id = AB8500_LDO_ANA, + .owner = THIS_MODULE, + .n_voltages = 1, + }, + .fixed_uV = 1200000, + .update_bank = 0x04, + .update_reg = 0x06, + .update_mask = 0x0c, + .update_val_enable = 0x04, + }, + + }; static __devinit int ab8500_regulator_probe(struct platform_device *pdev) -- cgit v0.10.2 From a1e516e3a5552519a01e8a7636569d2d1b68431f Mon Sep 17 00:00:00 2001 From: Bengt Jonsson Date: Fri, 10 Dec 2010 11:08:48 +0100 Subject: mach-ux500: Updated and connected ab8500 regulator board configuration The ab8500 regulator board configuration is updated and put in an array which can easily be used in the MFD board configuration. The regulator board configuration is also added to the MFD configuration in this patch. Signed-off-by: Bengt Jonsson Acked-by: Linus Walleij Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/arch/arm/mach-ux500/board-mop500-regulators.c b/arch/arm/mach-ux500/board-mop500-regulators.c index 1187f1f..533967c 100644 --- a/arch/arm/mach-ux500/board-mop500-regulators.c +++ b/arch/arm/mach-ux500/board-mop500-regulators.c @@ -3,99 +3,94 @@ * * License Terms: GNU General Public License v2 * - * Author: Sundar Iyer + * Authors: Sundar Iyer + * Bengt Jonsson * * MOP500 board specific initialization for regulators */ #include #include +#include -/* supplies to the display/camera */ -static struct regulator_init_data ab8500_vaux1_regulator = { - .constraints = { - .name = "V-DISPLAY", - .min_uV = 2500000, - .max_uV = 2900000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, +/* AB8500 regulators */ +struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS] = { + /* supplies to the display/camera */ + [AB8500_LDO_AUX1] = { + .constraints = { + .name = "V-DISPLAY", + .min_uV = 2500000, + .max_uV = 2900000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supplies to the on-board eMMC */ -static struct regulator_init_data ab8500_vaux2_regulator = { - .constraints = { - .name = "V-eMMC1", - .min_uV = 1100000, - .max_uV = 3300000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, + /* supplies to the on-board eMMC */ + [AB8500_LDO_AUX2] = { + .constraints = { + .name = "V-eMMC1", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for VAUX3, supplies to SDcard slots */ -static struct regulator_init_data ab8500_vaux3_regulator = { - .constraints = { - .name = "V-MMC-SD", - .min_uV = 1100000, - .max_uV = 3300000, - .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE| - REGULATOR_CHANGE_STATUS, + /* supply for VAUX3, supplies to SDcard slots */ + [AB8500_LDO_AUX3] = { + .constraints = { + .name = "V-MMC-SD", + .min_uV = 1100000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for tvout, gpadc, TVOUT LDO */ -static struct regulator_init_data ab8500_vtvout_init = { - .constraints = { - .name = "V-TVOUT", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for tvout, gpadc, TVOUT LDO */ + [AB8500_LDO_TVOUT] = { + .constraints = { + .name = "V-TVOUT", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for ab8500-vaudio, VAUDIO LDO */ -static struct regulator_init_data ab8500_vaudio_init = { - .constraints = { - .name = "V-AUD", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for ab8500-vaudio, VAUDIO LDO */ + [AB8500_LDO_AUDIO] = { + .constraints = { + .name = "V-AUD", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for v-anamic1 VAMic1-LDO */ -static struct regulator_init_data ab8500_vamic1_init = { - .constraints = { - .name = "V-AMIC1", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for v-anamic1 VAMic1-LDO */ + [AB8500_LDO_ANAMIC1] = { + .constraints = { + .name = "V-AMIC1", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ -static struct regulator_init_data ab8500_vamic2_init = { - .constraints = { - .name = "V-AMIC2", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for v-amic2, VAMIC2 LDO, reuse constants for AMIC1 */ + [AB8500_LDO_ANAMIC2] = { + .constraints = { + .name = "V-AMIC2", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for v-dmic, VDMIC LDO */ -static struct regulator_init_data ab8500_vdmic_init = { - .constraints = { - .name = "V-DMIC", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for v-dmic, VDMIC LDO */ + [AB8500_LDO_DMIC] = { + .constraints = { + .name = "V-DMIC", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for v-intcore12, VINTCORE12 LDO */ -static struct regulator_init_data ab8500_vintcore_init = { - .constraints = { - .name = "V-INTCORE", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for v-intcore12, VINTCORE12 LDO */ + [AB8500_LDO_INTCORE] = { + .constraints = { + .name = "V-INTCORE", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, -}; - -/* supply for U8500 CSI/DSI, VANA LDO */ -static struct regulator_init_data ab8500_vana_init = { - .constraints = { - .name = "V-CSI/DSI", - .valid_ops_mask = REGULATOR_CHANGE_STATUS, + /* supply for U8500 CSI/DSI, VANA LDO */ + [AB8500_LDO_ANA] = { + .constraints = { + .name = "V-CSI/DSI", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, }, }; - diff --git a/arch/arm/mach-ux500/board-mop500-regulators.h b/arch/arm/mach-ux500/board-mop500-regulators.h new file mode 100644 index 0000000..2675fae --- /dev/null +++ b/arch/arm/mach-ux500/board-mop500-regulators.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) ST-Ericsson SA 2010 + * + * License Terms: GNU General Public License v2 + * + * Author: Bengt Jonsson for ST-Ericsson + * + * MOP500 board specific initialization for regulators + */ + +#ifndef __BOARD_MOP500_REGULATORS_H +#define __BOARD_MOP500_REGULATORS_H + +#include +#include + +extern struct regulator_init_data ab8500_regulators[AB8500_NUM_REGULATORS]; + +#endif diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index a1c9ea1..a393f57 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -35,6 +35,7 @@ #include "devices-db8500.h" #include "pins-db8500.h" #include "board-mop500.h" +#include "board-mop500-regulators.h" static pin_cfg_t mop500_pins[] = { /* SSP0 */ @@ -80,6 +81,8 @@ static pin_cfg_t mop500_pins[] = { static struct ab8500_platform_data ab8500_platdata = { .irq_base = MOP500_AB8500_IRQ_BASE, + .regulator = ab8500_regulators, + .num_regulator = ARRAY_SIZE(ab8500_regulators), }; static struct resource ab8500_resources[] = { -- cgit v0.10.2 From 57c78e359a35c69eca4c88f107500f74ef7f0acf Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:53 +0800 Subject: Change the register name definitions for mc13783 To make mc13783 and mc13892 share code, the register names should be changed to fit the new macro definitions in the comming patch. Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Samuel Ortiz Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/arch/arm/mach-imx/mach-pcm038.c b/arch/arm/mach-imx/mach-pcm038.c index f667a26..5056148 100644 --- a/arch/arm/mach-imx/mach-pcm038.c +++ b/arch/arm/mach-imx/mach-pcm038.c @@ -254,10 +254,10 @@ static struct regulator_init_data cam_data = { static struct mc13783_regulator_init_data pcm038_regulators[] = { { - .id = MC13783_REGU_VCAM, + .id = MC13783_REG_VCAM, .init_data = &cam_data, }, { - .id = MC13783_REGU_VMMC1, + .id = MC13783_REG_VMMC1, .init_data = &sdhc1_data, }, }; diff --git a/arch/arm/mach-mx3/mach-mx31_3ds.c b/arch/arm/mach-mx3/mach-mx31_3ds.c index 4e516b4..899a969 100644 --- a/arch/arm/mach-mx3/mach-mx31_3ds.c +++ b/arch/arm/mach-mx3/mach-mx31_3ds.c @@ -140,10 +140,10 @@ static struct regulator_init_data gpo_init = { static struct mc13783_regulator_init_data mx31_3ds_regulators[] = { { - .id = MC13783_REGU_PWGT1SPI, /* Power Gate for ARM core. */ + .id = MC13783_REG_PWGT1SPI, /* Power Gate for ARM core. */ .init_data = &pwgtx_init, }, { - .id = MC13783_REGU_PWGT2SPI, /* Power Gate for L2 Cache. */ + .id = MC13783_REG_PWGT2SPI, /* Power Gate for L2 Cache. */ .init_data = &pwgtx_init, }, { diff --git a/arch/arm/mach-mx3/mach-mx31moboard.c b/arch/arm/mach-mx3/mach-mx31moboard.c index 203d21a..1aa8d65 100644 --- a/arch/arm/mach-mx3/mach-mx31moboard.c +++ b/arch/arm/mach-mx3/mach-mx31moboard.c @@ -216,11 +216,11 @@ static struct regulator_init_data cam_vreg_data = { static struct mc13783_regulator_init_data moboard_regulators[] = { { - .id = MC13783_REGU_VMMC1, + .id = MC13783_REG_VMMC1, .init_data = &sdhc_vreg_data, }, { - .id = MC13783_REGU_VCAM, + .id = MC13783_REG_VCAM, .init_data = &cam_vreg_data, }, }; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index e99917a..6a6e1d6 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -228,15 +228,15 @@ static struct regulator_ops mc13783_gpo_regulator_ops; } #define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(SW, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) #define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ - MC13783_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages) + MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) static struct mc13783_regulator mc13783_regulators[] = { MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), - MC13783_FIXED_DEFINE(REGU, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), - MC13783_FIXED_DEFINE(REGU, VIOHI, REGULATORMODE0, mc13783_viohi_val), + MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), + MC13783_FIXED_DEFINE(REG, VIOHI, REGULATORMODE0, mc13783_viohi_val), MC13783_DEFINE_REGU(VIOLO, REGULATORMODE0, REGULATORSETTING0, \ mc13783_violo_val), MC13783_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ @@ -255,7 +255,7 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vesim_val), MC13783_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ mc13783_vcam_val), - MC13783_FIXED_DEFINE(REGU, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), + MC13783_FIXED_DEFINE(REG, VRFBG, REGULATORMODE1, mc13783_vrfbg_val), MC13783_DEFINE_REGU(VVIB, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vvib_val), MC13783_DEFINE_REGU(VRF1, REGULATORMODE1, REGULATORSETTING1, \ @@ -266,12 +266,12 @@ static struct mc13783_regulator mc13783_regulators[] = { mc13783_vmmc_val), MC13783_DEFINE_REGU(VMMC2, REGULATORMODE1, REGULATORSETTING1, \ mc13783_vmmc_val), - MC13783_GPO_DEFINE(REGU, GPO1, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO2, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO3, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, GPO4, POWERMISC, mc13783_gpo_val), - MC13783_GPO_DEFINE(REGU, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), - MC13783_GPO_DEFINE(REGU, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, GPO1, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO2, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO3, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, GPO4, POWERMISC, mc13783_gpo_val), + MC13783_GPO_DEFINE(REG, PWGT1SPI, POWERMISC, mc13783_pwgtdrv_val), + MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), }; struct mc13783_regulator_priv { @@ -508,8 +508,8 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate enable value is 0 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) en_val = 0; mc13783_lock(priv->mc13783); @@ -530,8 +530,8 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); /* Power Gate disable value is 1 */ - if (id == MC13783_REGU_PWGT1SPI || - id == MC13783_REGU_PWGT2SPI) + if (id == MC13783_REG_PWGT1SPI || + id == MC13783_REG_PWGT2SPI) dis_val = mc13783_regulators[id].enable_bit; mc13783_lock(priv->mc13783); diff --git a/include/linux/mfd/mc13783.h b/include/linux/mfd/mc13783.h index b4c741e..7d0f3d6 100644 --- a/include/linux/mfd/mc13783.h +++ b/include/linux/mfd/mc13783.h @@ -1,4 +1,5 @@ /* + * Copyright 2010 Yong Shen * Copyright 2009-2010 Pengutronix * Uwe Kleine-Koenig * @@ -122,39 +123,39 @@ int mc13783_adc_do_conversion(struct mc13783 *mc13783, unsigned int mode, unsigned int channel, unsigned int *sample); -#define MC13783_SW_SW1A 0 -#define MC13783_SW_SW1B 1 -#define MC13783_SW_SW2A 2 -#define MC13783_SW_SW2B 3 -#define MC13783_SW_SW3 4 -#define MC13783_SW_PLL 5 -#define MC13783_REGU_VAUDIO 6 -#define MC13783_REGU_VIOHI 7 -#define MC13783_REGU_VIOLO 8 -#define MC13783_REGU_VDIG 9 -#define MC13783_REGU_VGEN 10 -#define MC13783_REGU_VRFDIG 11 -#define MC13783_REGU_VRFREF 12 -#define MC13783_REGU_VRFCP 13 -#define MC13783_REGU_VSIM 14 -#define MC13783_REGU_VESIM 15 -#define MC13783_REGU_VCAM 16 -#define MC13783_REGU_VRFBG 17 -#define MC13783_REGU_VVIB 18 -#define MC13783_REGU_VRF1 19 -#define MC13783_REGU_VRF2 20 -#define MC13783_REGU_VMMC1 21 -#define MC13783_REGU_VMMC2 22 -#define MC13783_REGU_GPO1 23 -#define MC13783_REGU_GPO2 24 -#define MC13783_REGU_GPO3 25 -#define MC13783_REGU_GPO4 26 -#define MC13783_REGU_V1 27 -#define MC13783_REGU_V2 28 -#define MC13783_REGU_V3 29 -#define MC13783_REGU_V4 30 -#define MC13783_REGU_PWGT1SPI 31 -#define MC13783_REGU_PWGT2SPI 32 +#define MC13783_REG_SW1A 0 +#define MC13783_REG_SW1B 1 +#define MC13783_REG_SW2A 2 +#define MC13783_REG_SW2B 3 +#define MC13783_REG_SW3 4 +#define MC13783_REG_PLL 5 +#define MC13783_REG_VAUDIO 6 +#define MC13783_REG_VIOHI 7 +#define MC13783_REG_VIOLO 8 +#define MC13783_REG_VDIG 9 +#define MC13783_REG_VGEN 10 +#define MC13783_REG_VRFDIG 11 +#define MC13783_REG_VRFREF 12 +#define MC13783_REG_VRFCP 13 +#define MC13783_REG_VSIM 14 +#define MC13783_REG_VESIM 15 +#define MC13783_REG_VCAM 16 +#define MC13783_REG_VRFBG 17 +#define MC13783_REG_VVIB 18 +#define MC13783_REG_VRF1 19 +#define MC13783_REG_VRF2 20 +#define MC13783_REG_VMMC1 21 +#define MC13783_REG_VMMC2 22 +#define MC13783_REG_GPO1 23 +#define MC13783_REG_GPO2 24 +#define MC13783_REG_GPO3 25 +#define MC13783_REG_GPO4 26 +#define MC13783_REG_V1 27 +#define MC13783_REG_V2 28 +#define MC13783_REG_V3 29 +#define MC13783_REG_V4 30 +#define MC13783_REG_PWGT1SPI 31 +#define MC13783_REG_PWGT2SPI 32 #define MC13783_IRQ_ADCDONE MC13XXX_IRQ_ADCDONE #define MC13783_IRQ_ADCBISDONE MC13XXX_IRQ_ADCBISDONE -- cgit v0.10.2 From 167e3d8af98a111994c4d6b3c5cbc589aedbbc2a Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:54 +0800 Subject: make mc13783 regulator code generic move some common functions and micros of mc13783 regulaor driver to a seperate file, which makes it possible for mc13892 to share code. Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index da34981..ce17a03 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -186,9 +186,13 @@ config REGULATOR_PCAP This driver provides support for the voltage regulators of the PCAP2 PMIC. +config REGULATOR_MC13XXX_CORE + bool + config REGULATOR_MC13783 tristate "Support regulators on Freescale MC13783 PMIC" depends on MFD_MC13783 + select REGULATOR_MC13XXX_CORE help Say y here to support the regulators found on the Freescale MC13783 PMIC. diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index cf71df7..0b33bac 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o +obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 6a6e1d6..3e5d0c3 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -1,6 +1,7 @@ /* * Regulator Driver for Freescale MC13783 PMIC * + * Copyright 2010 Yong Shen * Copyright (C) 2008 Sascha Hauer, Pengutronix * Copyright 2009 Alberto Panizzo * @@ -17,6 +18,7 @@ #include #include #include +#include "mc13xxx.h" #define MC13783_REG_SWITCHERS5 29 #define MC13783_REG_SWITCHERS5_SW3EN (1 << 20) @@ -89,16 +91,6 @@ #define MC13783_REG_POWERMISC_PWGTSPI_M (3 << 15) -struct mc13783_regulator { - struct regulator_desc desc; - int reg; - int enable_bit; - int vsel_reg; - int vsel_shift; - int vsel_mask; - int const *voltages; -}; - /* Voltage Values */ static const int mc13783_sw3_val[] = { 5000000, 5000000, 5000000, 5500000, @@ -175,64 +167,26 @@ static const int mc13783_pwgtdrv_val[] = { 5500000, }; -static struct regulator_ops mc13783_regulator_ops; -static struct regulator_ops mc13783_fixed_regulator_ops; static struct regulator_ops mc13783_gpo_regulator_ops; -#define MC13783_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .vsel_reg = MC13783_REG_ ## _vsel_reg, \ - .vsel_shift = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL,\ - .vsel_mask = MC13783_REG_ ## _vsel_reg ## _ ## _name ## VSEL_M,\ - .voltages = _voltages, \ - } +#define MC13783_DEFINE(prefix, name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13783_REG_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) -#define MC13783_FIXED_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_fixed_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_FIXED_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) -#define MC13783_GPO_DEFINE(prefix, _name, _reg, _voltages) \ - [MC13783_ ## prefix ## _ ## _name] = { \ - .desc = { \ - .name = #prefix "_" #_name, \ - .n_voltages = ARRAY_SIZE(_voltages), \ - .ops = &mc13783_gpo_regulator_ops, \ - .type = REGULATOR_VOLTAGE, \ - .id = MC13783_ ## prefix ## _ ## _name, \ - .owner = THIS_MODULE, \ - }, \ - .reg = MC13783_REG_ ## _reg, \ - .enable_bit = MC13783_REG_ ## _reg ## _ ## _name ## EN, \ - .voltages = _voltages, \ - } +#define MC13783_GPO_DEFINE(prefix, name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13783_REG_, name, reg, voltages, \ + mc13783_gpo_regulator_ops) #define MC13783_DEFINE_SW(_name, _reg, _vsel_reg, _voltages) \ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) #define MC13783_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages) \ MC13783_DEFINE(REG, _name, _reg, _vsel_reg, _voltages) -static struct mc13783_regulator mc13783_regulators[] = { +static struct mc13xxx_regulator mc13783_regulators[] = { MC13783_DEFINE_SW(SW3, SWITCHERS5, SWITCHERS5, mc13783_sw3_val), MC13783_FIXED_DEFINE(REG, VAUDIO, REGULATORMODE0, mc13783_vaudio_val), @@ -274,213 +228,16 @@ static struct mc13783_regulator mc13783_regulators[] = { MC13783_GPO_DEFINE(REG, PWGT2SPI, POWERMISC, mc13783_pwgtdrv_val), }; -struct mc13783_regulator_priv { - struct mc13783 *mc13783; - u32 powermisc_pwgt_state; - struct regulator_dev *regulators[]; -}; - -static int mc13783_regulator_enable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, - mc13783_regulators[id].enable_bit); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_disable(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].reg, - mc13783_regulators[id].enable_bit, 0); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - return (val & mc13783_regulators[id].enable_bit) != 0; -} - -static int mc13783_regulator_list_voltage(struct regulator_dev *rdev, - unsigned selector) -{ - int id = rdev_get_id(rdev); - - if (selector >= mc13783_regulators[id].desc.n_voltages) - return -EINVAL; - - return mc13783_regulators[id].voltages[selector]; -} - -static int mc13783_get_best_voltage_index(struct regulator_dev *rdev, - int min_uV, int max_uV) -{ - int reg_id = rdev_get_id(rdev); - int i; - int bestmatch; - int bestindex; - - /* - * Locate the minimum voltage fitting the criteria on - * this regulator. The switchable voltages are not - * in strict falling order so we need to check them - * all for the best match. - */ - bestmatch = INT_MAX; - bestindex = -1; - for (i = 0; i < mc13783_regulators[reg_id].desc.n_voltages; i++) { - if (mc13783_regulators[reg_id].voltages[i] >= min_uV && - mc13783_regulators[reg_id].voltages[i] < bestmatch) { - bestmatch = mc13783_regulators[reg_id].voltages[i]; - bestindex = i; - } - } - - if (bestindex < 0 || bestmatch > max_uV) { - dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", - min_uV, max_uV); - return -EINVAL; - } - return bestindex; -} - -static int mc13783_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned *selector) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int value, id = rdev_get_id(rdev); - int ret; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - /* Find the best index */ - value = mc13783_get_best_voltage_index(rdev, min_uV, max_uV); - dev_dbg(rdev_get_dev(rdev), "%s best value: %d \n", __func__, value); - if (value < 0) - return value; - - *selector = value; - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_rmw(priv->mc13783, mc13783_regulators[id].vsel_reg, - mc13783_regulators[id].vsel_mask, - value << mc13783_regulators[id].vsel_shift); - mc13783_unlock(priv->mc13783); - - return ret; -} - -static int mc13783_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); - int ret, id = rdev_get_id(rdev); - unsigned int val; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, - mc13783_regulators[id].vsel_reg, &val); - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - val = (val & mc13783_regulators[id].vsel_mask) - >> mc13783_regulators[id].vsel_shift; - - dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); - - BUG_ON(val < 0 || val > mc13783_regulators[id].desc.n_voltages); - - return mc13783_regulators[id].voltages[val]; -} - -static struct regulator_ops mc13783_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_regulator_set_voltage, - .get_voltage = mc13783_regulator_get_voltage, -}; - -static int mc13783_fixed_regulator_set_voltage(struct regulator_dev *rdev, - int min_uV, int max_uV, - unsigned int *selector) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", - __func__, id, min_uV, max_uV); - - *selector = 0; - - if (min_uV >= mc13783_regulators[id].voltages[0] && - max_uV <= mc13783_regulators[id].voltages[0]) - return 0; - else - return -EINVAL; -} - -static int mc13783_fixed_regulator_get_voltage(struct regulator_dev *rdev) -{ - int id = rdev_get_id(rdev); - - dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); - - return mc13783_regulators[id].voltages[0]; -} - -static struct regulator_ops mc13783_fixed_regulator_ops = { - .enable = mc13783_regulator_enable, - .disable = mc13783_regulator_disable, - .is_enabled = mc13783_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, -}; - -static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, - u32 val) +static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) { - struct mc13783 *mc13783 = priv->mc13783; + struct mc13xxx *mc13783 = priv->mc13xxx; int ret; u32 valread; BUG_ON(val & ~mask); - ret = mc13783_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); + ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread); if (ret) return ret; @@ -495,15 +252,16 @@ static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) | priv->powermisc_pwgt_state; - return mc13783_reg_write(mc13783, MC13783_REG_POWERMISC, valread); + return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread); } static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; - u32 en_val = mc13783_regulators[id].enable_bit; + u32 en_val = mc13xxx_regulators[id].enable_bit; dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); @@ -512,17 +270,18 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev) id == MC13783_REG_PWGT2SPI) en_val = 0; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, en_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int id = rdev_get_id(rdev); int ret; u32 dis_val = 0; @@ -532,25 +291,26 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev) /* Power Gate disable value is 1 */ if (id == MC13783_REG_PWGT1SPI || id == MC13783_REG_PWGT2SPI) - dis_val = mc13783_regulators[id].enable_bit; + dis_val = mc13xxx_regulators[id].enable_bit; - mc13783_lock(priv->mc13783); - ret = mc13783_powermisc_rmw(priv, mc13783_regulators[id].enable_bit, + mc13xxx_lock(priv->mc13xxx); + ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit, dis_val); - mc13783_unlock(priv->mc13783); + mc13xxx_unlock(priv->mc13xxx); return ret; } static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) { - struct mc13783_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; int ret, id = rdev_get_id(rdev); unsigned int val; - mc13783_lock(priv->mc13783); - ret = mc13783_reg_read(priv->mc13783, mc13783_regulators[id].reg, &val); - mc13783_unlock(priv->mc13783); + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); if (ret) return ret; @@ -560,22 +320,22 @@ static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev) val = (val & ~MC13783_REG_POWERMISC_PWGTSPI_M) | (priv->powermisc_pwgt_state ^ MC13783_REG_POWERMISC_PWGTSPI_M); - return (val & mc13783_regulators[id].enable_bit) != 0; + return (val & mc13xxx_regulators[id].enable_bit) != 0; } static struct regulator_ops mc13783_gpo_regulator_ops = { .enable = mc13783_gpo_regulator_enable, .disable = mc13783_gpo_regulator_disable, .is_enabled = mc13783_gpo_regulator_is_enabled, - .list_voltage = mc13783_regulator_list_voltage, - .set_voltage = mc13783_fixed_regulator_set_voltage, - .get_voltage = mc13783_fixed_regulator_get_voltage, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; static int __devinit mc13783_regulator_probe(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv; - struct mc13783 *mc13783 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); struct mc13783_regulator_init_data *init_data; @@ -589,7 +349,8 @@ static int __devinit mc13783_regulator_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - priv->mc13783 = mc13783; + priv->mc13xxx_regulators = mc13783_regulators; + priv->mc13xxx = mc13783; for (i = 0; i < pdata->num_regulators; i++) { init_data = &pdata->regulators[i]; @@ -619,7 +380,7 @@ err: static int __devexit mc13783_regulator_remove(struct platform_device *pdev) { - struct mc13783_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); struct mc13783_regulator_platform_data *pdata = dev_get_platdata(&pdev->dev); int i; diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c new file mode 100644 index 0000000..448e8f4 --- /dev/null +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -0,0 +1,234 @@ +/* + * Regulator Driver for Freescale MC13xxx PMIC + * + * Copyright 2010 Yong Shen + * + * Based on mc13783 regulator driver : + * Copyright (C) 2008 Sascha Hauer, Pengutronix + * Copyright 2009 Alberto Panizzo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Regs infos taken from mc13xxx drivers from freescale and mc13xxx.pdf file + * from freescale + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mc13xxx.h" + +static int mc13xxx_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, + mc13xxx_regulators[id].enable_bit); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].reg, + mc13xxx_regulators[id].enable_bit, 0); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13xxx_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + return (val & mc13xxx_regulators[id].enable_bit) != 0; +} + +int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector) +{ + int id = rdev_get_id(rdev); + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + + if (selector >= mc13xxx_regulators[id].desc.n_voltages) + return -EINVAL; + + return mc13xxx_regulators[id].voltages[selector]; +} + +int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int reg_id = rdev_get_id(rdev); + int i; + int bestmatch; + int bestindex; + + /* + * Locate the minimum voltage fitting the criteria on + * this regulator. The switchable voltages are not + * in strict falling order so we need to check them + * all for the best match. + */ + bestmatch = INT_MAX; + bestindex = -1; + for (i = 0; i < mc13xxx_regulators[reg_id].desc.n_voltages; i++) { + if (mc13xxx_regulators[reg_id].voltages[i] >= min_uV && + mc13xxx_regulators[reg_id].voltages[i] < bestmatch) { + bestmatch = mc13xxx_regulators[reg_id].voltages[i]; + bestindex = i; + } + } + + if (bestindex < 0 || bestmatch > max_uV) { + dev_warn(&rdev->dev, "no possible value for %d<=x<=%d uV\n", + min_uV, max_uV); + return -EINVAL; + } + return bestindex; +} + +static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int value, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13xxx_regulators[id].vsel_reg, + mc13xxx_regulators[id].vsel_mask, + value << mc13xxx_regulators[id].vsel_shift); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13xxx_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int ret, id = rdev_get_id(rdev); + unsigned int val; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13xxx_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + val = (val & mc13xxx_regulators[id].vsel_mask) + >> mc13xxx_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + BUG_ON(val < 0 || val > mc13xxx_regulators[id].desc.n_voltages); + + return mc13xxx_regulators[id].voltages[val]; +} + +struct regulator_ops mc13xxx_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_regulator_set_voltage, + .get_voltage = mc13xxx_regulator_get_voltage, +}; + +int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, + int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + if (min_uV >= mc13xxx_regulators[id].voltages[0] && + max_uV <= mc13xxx_regulators[id].voltages[0]) + return 0; + else + return -EINVAL; +} + +int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators; + int id = rdev_get_id(rdev); + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + return mc13xxx_regulators[id].voltages[0]; +} + +struct regulator_ops mc13xxx_fixed_regulator_ops = { + .enable = mc13xxx_regulator_enable, + .disable = mc13xxx_regulator_disable, + .is_enabled = mc13xxx_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; + +int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) +{ + return 1; +} + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen "); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13xxx PMIC"); +MODULE_ALIAS("mc13xxx-regulator-core"); diff --git a/drivers/regulator/mc13xxx.h b/drivers/regulator/mc13xxx.h new file mode 100644 index 0000000..2775826 --- /dev/null +++ b/drivers/regulator/mc13xxx.h @@ -0,0 +1,101 @@ +/* + * mc13xxx.h - regulators for the Freescale mc13xxx PMIC + * + * Copyright (C) 2010 Yong Shen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_REGULATOR_MC13XXX_H +#define __LINUX_REGULATOR_MC13XXX_H + +#include + +struct mc13xxx_regulator { + struct regulator_desc desc; + int reg; + int enable_bit; + int vsel_reg; + int vsel_shift; + int vsel_mask; + int hi_bit; + int const *voltages; +}; + +struct mc13xxx_regulator_priv { + struct mc13xxx *mc13xxx; + u32 powermisc_pwgt_state; + struct mc13xxx_regulator *mc13xxx_regulators; + struct regulator_dev *regulators[]; +}; + +extern int mc13xxx_sw_regulator(struct regulator_dev *rdev); +extern int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev); +extern int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, + int min_uV, int max_uV); +extern int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, + unsigned selector); +extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector); +extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev); + +extern struct regulator_ops mc13xxx_regulator_ops; +extern struct regulator_ops mc13xxx_fixed_regulator_ops; + +#define MC13xxx_DEFINE(prefix, _name, _reg, _vsel_reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .vsel_reg = prefix ## _vsel_reg, \ + .vsel_shift = prefix ## _vsel_reg ## _ ## _name ## VSEL,\ + .vsel_mask = prefix ## _vsel_reg ## _ ## _name ## VSEL_M,\ + .voltages = _voltages, \ + } + +#define MC13xxx_FIXED_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_GPO_DEFINE(prefix, _name, _reg, _voltages, _ops) \ + [prefix ## _name] = { \ + .desc = { \ + .name = #prefix "_" #_name, \ + .n_voltages = ARRAY_SIZE(_voltages), \ + .ops = &_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = prefix ## _name, \ + .owner = THIS_MODULE, \ + }, \ + .reg = prefix ## _reg, \ + .enable_bit = prefix ## _reg ## _ ## _name ## EN, \ + .voltages = _voltages, \ + } + +#define MC13xxx_DEFINE_SW(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(SW, _name, _reg, _vsel_reg, _voltages, ops) +#define MC13xxx_DEFINE_REGU(_name, _reg, _vsel_reg, _voltages, ops) \ + MC13xxx_DEFINE(REGU, _name, _reg, _vsel_reg, _voltages, ops) + +#endif -- cgit v0.10.2 From 5e428d5cecc3f109b52e993a1bd91f82137867b3 Mon Sep 17 00:00:00 2001 From: Yong Shen Date: Tue, 14 Dec 2010 14:00:55 +0800 Subject: regulator: support PMIC mc13892 add support for mc13892, tested on mx51 babbage board Signed-off-by: Arnaud Patard Signed-off-by: Yong Shen Acked-by: Sascha Hauer Acked-by: Samuel Ortiz Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index ce17a03..485a9bc 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -197,6 +197,14 @@ config REGULATOR_MC13783 Say y here to support the regulators found on the Freescale MC13783 PMIC. +config REGULATOR_MC13892 + tristate "Support regulators on Freescale MC13892 PMIC" + depends on MFD_MC13XXX + select REGULATOR_MC13XXX_CORE + help + Say y here to support the regulators found on the Freescale MC13892 + PMIC. + config REGULATOR_AB3100 tristate "ST-Ericsson AB3100 Regulator functions" depends on AB3100_CORE diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 0b33bac..0b5e88c 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o +obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c new file mode 100644 index 0000000..ca1d30a --- /dev/null +++ b/drivers/regulator/mc13892-regulator.c @@ -0,0 +1,635 @@ +/* + * Regulator Driver for Freescale MC13892 PMIC + * + * Copyright 2010 Yong Shen + * + * Based on draft driver from Arnaud Patard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "mc13xxx.h" + +#define MC13892_REVISION 7 + +#define MC13892_POWERCTL0 13 +#define MC13892_POWERCTL0_USEROFFSPI 3 +#define MC13892_POWERCTL0_VCOINCELLVSEL 20 +#define MC13892_POWERCTL0_VCOINCELLVSEL_M (7<<20) +#define MC13892_POWERCTL0_VCOINCELLEN (1<<23) + +#define MC13892_SWITCHERS0_SWxHI (1<<23) + +#define MC13892_SWITCHERS0 24 +#define MC13892_SWITCHERS0_SW1VSEL 0 +#define MC13892_SWITCHERS0_SW1VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS0_SW1HI (1<<23) +#define MC13892_SWITCHERS0_SW1EN 0 + +#define MC13892_SWITCHERS1 25 +#define MC13892_SWITCHERS1_SW2VSEL 0 +#define MC13892_SWITCHERS1_SW2VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS1_SW2HI (1<<23) +#define MC13892_SWITCHERS1_SW2EN 0 + +#define MC13892_SWITCHERS2 26 +#define MC13892_SWITCHERS2_SW3VSEL 0 +#define MC13892_SWITCHERS2_SW3VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS2_SW3HI (1<<23) +#define MC13892_SWITCHERS2_SW3EN 0 + +#define MC13892_SWITCHERS3 27 +#define MC13892_SWITCHERS3_SW4VSEL 0 +#define MC13892_SWITCHERS3_SW4VSEL_M (0x1f<<0) +#define MC13892_SWITCHERS3_SW4HI (1<<23) +#define MC13892_SWITCHERS3_SW4EN 0 + +#define MC13892_SWITCHERS4 28 +#define MC13892_SWITCHERS4_SW1MODE 0 +#define MC13892_SWITCHERS4_SW1MODE_AUTO (8<<0) +#define MC13892_SWITCHERS4_SW1MODE_M (0xf<<0) +#define MC13892_SWITCHERS4_SW2MODE 10 +#define MC13892_SWITCHERS4_SW2MODE_AUTO (8<<10) +#define MC13892_SWITCHERS4_SW2MODE_M (0xf<<10) + +#define MC13892_SWITCHERS5 29 +#define MC13892_SWITCHERS5_SW3MODE 0 +#define MC13892_SWITCHERS5_SW3MODE_AUTO (8<<0) +#define MC13892_SWITCHERS5_SW3MODE_M (0xf<<0) +#define MC13892_SWITCHERS5_SW4MODE 8 +#define MC13892_SWITCHERS5_SW4MODE_AUTO (8<<8) +#define MC13892_SWITCHERS5_SW4MODE_M (0xf<<8) +#define MC13892_SWITCHERS5_SWBSTEN (1<<20) + +#define MC13892_REGULATORSETTING0 30 +#define MC13892_REGULATORSETTING0_VGEN1VSEL 0 +#define MC13892_REGULATORSETTING0_VDIGVSEL 4 +#define MC13892_REGULATORSETTING0_VGEN2VSEL 6 +#define MC13892_REGULATORSETTING0_VPLLVSEL 9 +#define MC13892_REGULATORSETTING0_VUSB2VSEL 11 +#define MC13892_REGULATORSETTING0_VGEN3VSEL 14 +#define MC13892_REGULATORSETTING0_VCAMVSEL 16 + +#define MC13892_REGULATORSETTING0_VGEN1VSEL_M (3<<0) +#define MC13892_REGULATORSETTING0_VDIGVSEL_M (3<<4) +#define MC13892_REGULATORSETTING0_VGEN2VSEL_M (7<<6) +#define MC13892_REGULATORSETTING0_VPLLVSEL_M (3<<9) +#define MC13892_REGULATORSETTING0_VUSB2VSEL_M (3<<11) +#define MC13892_REGULATORSETTING0_VGEN3VSEL_M (1<<14) +#define MC13892_REGULATORSETTING0_VCAMVSEL_M (3<<16) + +#define MC13892_REGULATORSETTING1 31 +#define MC13892_REGULATORSETTING1_VVIDEOVSEL 2 +#define MC13892_REGULATORSETTING1_VAUDIOVSEL 4 +#define MC13892_REGULATORSETTING1_VSDVSEL 6 + +#define MC13892_REGULATORSETTING1_VVIDEOVSEL_M (3<<2) +#define MC13892_REGULATORSETTING1_VAUDIOVSEL_M (3<<4) +#define MC13892_REGULATORSETTING1_VSDVSEL_M (7<<6) + +#define MC13892_REGULATORMODE0 32 +#define MC13892_REGULATORMODE0_VGEN1EN (1<<0) +#define MC13892_REGULATORMODE0_VGEN1STDBY (1<<1) +#define MC13892_REGULATORMODE0_VGEN1MODE (1<<2) +#define MC13892_REGULATORMODE0_VIOHIEN (1<<3) +#define MC13892_REGULATORMODE0_VIOHISTDBY (1<<4) +#define MC13892_REGULATORMODE0_VIOHIMODE (1<<5) +#define MC13892_REGULATORMODE0_VDIGEN (1<<9) +#define MC13892_REGULATORMODE0_VDIGSTDBY (1<<10) +#define MC13892_REGULATORMODE0_VDIGMODE (1<<11) +#define MC13892_REGULATORMODE0_VGEN2EN (1<<12) +#define MC13892_REGULATORMODE0_VGEN2STDBY (1<<13) +#define MC13892_REGULATORMODE0_VGEN2MODE (1<<14) +#define MC13892_REGULATORMODE0_VPLLEN (1<<15) +#define MC13892_REGULATORMODE0_VPLLSTDBY (1<<16) +#define MC13892_REGULATORMODE0_VPLLMODE (1<<17) +#define MC13892_REGULATORMODE0_VUSB2EN (1<<18) +#define MC13892_REGULATORMODE0_VUSB2STDBY (1<<19) +#define MC13892_REGULATORMODE0_VUSB2MODE (1<<20) + +#define MC13892_REGULATORMODE1 33 +#define MC13892_REGULATORMODE1_VGEN3EN (1<<0) +#define MC13892_REGULATORMODE1_VGEN3STDBY (1<<1) +#define MC13892_REGULATORMODE1_VGEN3MODE (1<<2) +#define MC13892_REGULATORMODE1_VCAMEN (1<<6) +#define MC13892_REGULATORMODE1_VCAMSTDBY (1<<7) +#define MC13892_REGULATORMODE1_VCAMMODE (1<<8) +#define MC13892_REGULATORMODE1_VCAMCONFIGEN (1<<9) +#define MC13892_REGULATORMODE1_VVIDEOEN (1<<12) +#define MC13892_REGULATORMODE1_VVIDEOSTDBY (1<<13) +#define MC13892_REGULATORMODE1_VVIDEOMODE (1<<14) +#define MC13892_REGULATORMODE1_VAUDIOEN (1<<15) +#define MC13892_REGULATORMODE1_VAUDIOSTDBY (1<<16) +#define MC13892_REGULATORMODE1_VAUDIOMODE (1<<17) +#define MC13892_REGULATORMODE1_VSDEN (1<<18) +#define MC13892_REGULATORMODE1_VSDSTDBY (1<<19) +#define MC13892_REGULATORMODE1_VSDMODE (1<<20) + +#define MC13892_POWERMISC 34 +#define MC13892_POWERMISC_GPO1EN (1<<6) +#define MC13892_POWERMISC_GPO2EN (1<<8) +#define MC13892_POWERMISC_GPO3EN (1<<10) +#define MC13892_POWERMISC_GPO4EN (1<<12) +#define MC13892_POWERMISC_PWGT1SPIEN (1<<15) +#define MC13892_POWERMISC_PWGT2SPIEN (1<<16) +#define MC13892_POWERMISC_GPO4ADINEN (1<<21) + +#define MC13892_POWERMISC_PWGTSPI_M (3 << 15) + +#define MC13892_USB1 50 +#define MC13892_USB1_VUSBEN (1<<3) + +static const int mc13892_vcoincell[] = { + 2500000, 2700000, 2800000, 2900000, 3000000, 3100000, + 3200000, 3300000, +}; + +static const int mc13892_sw1[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000 +}; + +static const int mc13892_sw[] = { + 600000, 625000, 650000, 675000, 700000, 725000, + 750000, 775000, 800000, 825000, 850000, 875000, + 900000, 925000, 950000, 975000, 1000000, 1025000, + 1050000, 1075000, 1100000, 1125000, 1150000, 1175000, + 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, + 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, + 1500000, 1525000, 1550000, 1575000, 1600000, 1625000, + 1650000, 1675000, 1700000, 1725000, 1750000, 1775000, + 1800000, 1825000, 1850000, 1875000 +}; + +static const int mc13892_swbst[] = { + 5000000, +}; + +static const int mc13892_viohi[] = { + 2775000, +}; + +static const int mc13892_vpll[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vdig[] = { + 1050000, 1250000, 1650000, 1800000, +}; + +static const int mc13892_vsd[] = { + 1800000, 2000000, 2600000, 2700000, + 2800000, 2900000, 3000000, 3150000, +}; + +static const int mc13892_vusb2[] = { + 2400000, 2600000, 2700000, 2775000, +}; + +static const int mc13892_vvideo[] = { + 2700000, 2775000, 2500000, 2600000, +}; + +static const int mc13892_vaudio[] = { + 2300000, 2500000, 2775000, 3000000, +}; + +static const int mc13892_vcam[] = { + 2500000, 2600000, 2750000, 3000000, +}; + +static const int mc13892_vgen1[] = { + 1200000, 1500000, 2775000, 3150000, +}; + +static const int mc13892_vgen2[] = { + 1200000, 1500000, 1600000, 1800000, + 2700000, 2800000, 3000000, 3150000, +}; + +static const int mc13892_vgen3[] = { + 1800000, 2900000, +}; + +static const int mc13892_vusb[] = { + 3300000, +}; + +static const int mc13892_gpo[] = { + 2750000, +}; + +static const int mc13892_pwgtdrv[] = { + 5000000, +}; + +static struct regulator_ops mc13892_gpo_regulator_ops; +/* sw regulators need special care due to the "hi bit" */ +static struct regulator_ops mc13892_sw_regulator_ops; + + +#define MC13892_FIXED_DEFINE(name, reg, voltages) \ + MC13xxx_FIXED_DEFINE(MC13892_, name, reg, voltages, \ + mc13xxx_fixed_regulator_ops) + +#define MC13892_GPO_DEFINE(name, reg, voltages) \ + MC13xxx_GPO_DEFINE(MC13892_, name, reg, voltages, \ + mc13892_gpo_regulator_ops) + +#define MC13892_SW_DEFINE(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13892_sw_regulator_ops) + +#define MC13892_DEFINE_REGU(name, reg, vsel_reg, voltages) \ + MC13xxx_DEFINE(MC13892_, name, reg, vsel_reg, voltages, \ + mc13xxx_regulator_ops) + +static struct mc13xxx_regulator mc13892_regulators[] = { + MC13892_DEFINE_REGU(VCOINCELL, POWERCTL0, POWERCTL0, mc13892_vcoincell), + MC13892_SW_DEFINE(SW1, SWITCHERS0, SWITCHERS0, mc13892_sw1), + MC13892_SW_DEFINE(SW2, SWITCHERS1, SWITCHERS1, mc13892_sw), + MC13892_SW_DEFINE(SW3, SWITCHERS2, SWITCHERS2, mc13892_sw), + MC13892_SW_DEFINE(SW4, SWITCHERS3, SWITCHERS3, mc13892_sw), + MC13892_FIXED_DEFINE(SWBST, SWITCHERS5, mc13892_swbst), + MC13892_FIXED_DEFINE(VIOHI, REGULATORMODE0, mc13892_viohi), + MC13892_DEFINE_REGU(VPLL, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vpll), + MC13892_DEFINE_REGU(VDIG, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vdig), + MC13892_DEFINE_REGU(VSD, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vsd), + MC13892_DEFINE_REGU(VUSB2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vusb2), + MC13892_DEFINE_REGU(VVIDEO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vvideo), + MC13892_DEFINE_REGU(VAUDIO, REGULATORMODE1, REGULATORSETTING1, \ + mc13892_vaudio), + MC13892_DEFINE_REGU(VCAM, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vcam), + MC13892_DEFINE_REGU(VGEN1, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen1), + MC13892_DEFINE_REGU(VGEN2, REGULATORMODE0, REGULATORSETTING0, \ + mc13892_vgen2), + MC13892_DEFINE_REGU(VGEN3, REGULATORMODE1, REGULATORSETTING0, \ + mc13892_vgen3), + MC13892_FIXED_DEFINE(VUSB, USB1, mc13892_vusb), + MC13892_GPO_DEFINE(GPO1, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO2, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO3, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(GPO4, POWERMISC, mc13892_gpo), + MC13892_GPO_DEFINE(PWGT1SPI, POWERMISC, mc13892_pwgtdrv), + MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), +}; + +int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) +{ + struct mc13xxx *mc13892 = priv->mc13xxx; + int ret; + u32 valread; + + BUG_ON(val & ~mask); + + ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread); + if (ret) + return ret; + + /* Update the stored state for Power Gates. */ + priv->powermisc_pwgt_state = + (priv->powermisc_pwgt_state & ~mask) | val; + priv->powermisc_pwgt_state &= MC13892_POWERMISC_PWGTSPI_M; + + /* Construct the new register value */ + valread = (valread & ~mask) | val; + /* Overwrite the PWGTxEN with the stored version */ + valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) | + priv->powermisc_pwgt_state; + + return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread); +} + +static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 en_val = mc13892_regulators[id].enable_bit; + u32 mask = mc13892_regulators[id].enable_bit; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate enable value is 0 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + en_val = 0; + + if (id == MC13892_GPO4) + mask |= MC13892_POWERMISC_GPO4ADINEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mask, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int id = rdev_get_id(rdev); + int ret; + u32 dis_val = 0; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + /* Power Gate disable value is 1 */ + if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI) + dis_val = mc13892_regulators[id].enable_bit; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit, + dis_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + /* Power Gates state is stored in powermisc_pwgt_state + * where the meaning of bits is negated */ + val = (val & ~MC13892_POWERMISC_PWGTSPI_M) | + (priv->powermisc_pwgt_state ^ MC13892_POWERMISC_PWGTSPI_M); + + return (val & mc13892_regulators[id].enable_bit) != 0; +} + + +static struct regulator_ops mc13892_gpo_regulator_ops = { + .enable = mc13892_gpo_regulator_enable, + .disable = mc13892_gpo_regulator_disable, + .is_enabled = mc13892_gpo_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13xxx_fixed_regulator_set_voltage, + .get_voltage = mc13xxx_fixed_regulator_get_voltage, +}; + +static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val, hi; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id); + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + mc13xxx_unlock(priv->mc13xxx); + if (ret) + return ret; + + hi = val & MC13892_SWITCHERS0_SWxHI; + val = (val & mc13892_regulators[id].vsel_mask) + >> mc13892_regulators[id].vsel_shift; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val); + + if (hi) + val = (25000 * val) + 1100000; + else + val = (25000 * val) + 600000; + + return val; +} + +static int mc13892_sw_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, unsigned *selector) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int hi, value, val, mask, id = rdev_get_id(rdev); + int ret; + + dev_dbg(rdev_get_dev(rdev), "%s id: %d min_uV: %d max_uV: %d\n", + __func__, id, min_uV, max_uV); + + /* Find the best index */ + value = mc13xxx_get_best_voltage_index(rdev, min_uV, max_uV); + dev_dbg(rdev_get_dev(rdev), "%s best value: %d\n", __func__, value); + if (value < 0) + return value; + + value = mc13892_regulators[id].voltages[value]; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, + mc13892_regulators[id].vsel_reg, &val); + if (ret) + goto err; + + hi = val & MC13892_SWITCHERS0_SWxHI; + if (value > 1375) + hi = 1; + if (value < 1100) + hi = 0; + + if (hi) { + value = (value - 1100000) / 25000; + value |= MC13892_SWITCHERS0_SWxHI; + } else + value = (value - 600000) / 25000; + + mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI; + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].vsel_reg, + mask, value << mc13892_regulators[id].vsel_shift); +err: + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +static struct regulator_ops mc13892_sw_regulator_ops = { + .is_enabled = mc13xxx_sw_regulator_is_enabled, + .list_voltage = mc13xxx_regulator_list_voltage, + .set_voltage = mc13892_sw_regulator_set_voltage, + .get_voltage = mc13892_sw_regulator_get_voltage, +}; + +static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + unsigned int en_val = 0; + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + + if (mode == REGULATOR_MODE_FAST) + en_val = MC13892_REGULATORMODE1_VCAMCONFIGEN; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, + MC13892_REGULATORMODE1_VCAMCONFIGEN, en_val); + mc13xxx_unlock(priv->mc13xxx); + + return ret; +} + +unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) +{ + struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); + int ret, id = rdev_get_id(rdev); + unsigned int val; + + mc13xxx_lock(priv->mc13xxx); + ret = mc13xxx_reg_read(priv->mc13xxx, mc13892_regulators[id].reg, &val); + mc13xxx_unlock(priv->mc13xxx); + + if (ret) + return ret; + + if (val & MC13892_REGULATORMODE1_VCAMCONFIGEN) + return REGULATOR_MODE_FAST; + + return REGULATOR_MODE_NORMAL; +} + + +static int __devinit mc13892_regulator_probe(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv; + struct mc13xxx *mc13892 = dev_get_drvdata(pdev->dev.parent); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + struct mc13xxx_regulator_init_data *init_data; + int i, ret; + u32 val; + + priv = kzalloc(sizeof(*priv) + + pdata->num_regulators * sizeof(priv->regulators[0]), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->mc13xxx_regulators = mc13892_regulators; + priv->mc13xxx = mc13892; + + mc13xxx_lock(mc13892); + ret = mc13xxx_reg_read(mc13892, MC13892_REVISION, &val); + if (ret) + goto err_free; + + /* enable switch auto mode */ + if ((val & 0x0000FFFF) == 0x45d0) { + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS4, + MC13892_SWITCHERS4_SW1MODE_M | + MC13892_SWITCHERS4_SW2MODE_M, + MC13892_SWITCHERS4_SW1MODE_AUTO | + MC13892_SWITCHERS4_SW2MODE_AUTO); + if (ret) + goto err_free; + + mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, + MC13892_SWITCHERS5_SW3MODE_M | + MC13892_SWITCHERS5_SW4MODE_M, + MC13892_SWITCHERS5_SW3MODE_AUTO | + MC13892_SWITCHERS5_SW4MODE_AUTO); + if (ret) + goto err_free; + } + mc13xxx_unlock(mc13892); + + mc13892_regulators[MC13892_VCAM].desc.ops->set_mode + = mc13892_vcam_set_mode; + mc13892_regulators[MC13892_VCAM].desc.ops->get_mode + = mc13892_vcam_get_mode; + for (i = 0; i < pdata->num_regulators; i++) { + init_data = &pdata->regulators[i]; + priv->regulators[i] = regulator_register( + &mc13892_regulators[init_data->id].desc, + &pdev->dev, init_data->init_data, priv); + + if (IS_ERR(priv->regulators[i])) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + mc13892_regulators[i].desc.name); + ret = PTR_ERR(priv->regulators[i]); + goto err; + } + } + + platform_set_drvdata(pdev, priv); + + return 0; +err: + while (--i >= 0) + regulator_unregister(priv->regulators[i]); + +err_free: + mc13xxx_unlock(mc13892); + kfree(priv); + + return ret; +} + +static int __devexit mc13892_regulator_remove(struct platform_device *pdev) +{ + struct mc13xxx_regulator_priv *priv = platform_get_drvdata(pdev); + struct mc13xxx_regulator_platform_data *pdata = + dev_get_platdata(&pdev->dev); + int i; + + platform_set_drvdata(pdev, NULL); + + for (i = 0; i < pdata->num_regulators; i++) + regulator_unregister(priv->regulators[i]); + + kfree(priv); + return 0; +} + +static struct platform_driver mc13892_regulator_driver = { + .driver = { + .name = "mc13892-regulator", + .owner = THIS_MODULE, + }, + .remove = __devexit_p(mc13892_regulator_remove), + .probe = mc13892_regulator_probe, +}; + +static int __init mc13892_regulator_init(void) +{ + return platform_driver_register(&mc13892_regulator_driver); +} +subsys_initcall(mc13892_regulator_init); + +static void __exit mc13892_regulator_exit(void) +{ + platform_driver_unregister(&mc13892_regulator_driver); +} +module_exit(mc13892_regulator_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yong Shen "); +MODULE_DESCRIPTION("Regulator Driver for Freescale MC13892 PMIC"); +MODULE_ALIAS("platform:mc13892-regulator"); diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h new file mode 100644 index 0000000..a00f2be --- /dev/null +++ b/include/linux/mfd/mc13892.h @@ -0,0 +1,39 @@ +/* + * Copyright 2010 Yong Shen + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ + +#ifndef __LINUX_MFD_MC13892_H +#define __LINUX_MFD_MC13892_H + +#include + +#define MC13892_SW1 0 +#define MC13892_SW2 1 +#define MC13892_SW3 2 +#define MC13892_SW4 3 +#define MC13892_SWBST 4 +#define MC13892_VIOHI 5 +#define MC13892_VPLL 6 +#define MC13892_VDIG 7 +#define MC13892_VSD 8 +#define MC13892_VUSB2 9 +#define MC13892_VVIDEO 10 +#define MC13892_VAUDIO 11 +#define MC13892_VCAM 12 +#define MC13892_VGEN1 13 +#define MC13892_VGEN2 14 +#define MC13892_VGEN3 15 +#define MC13892_VUSB 16 +#define MC13892_GPO1 17 +#define MC13892_GPO2 18 +#define MC13892_GPO3 19 +#define MC13892_GPO4 20 +#define MC13892_PWGT1SPI 21 +#define MC13892_PWGT2SPI 22 +#define MC13892_VCOINCELL 23 + +#endif -- cgit v0.10.2 From 4d7071f1fdc9c27e15e8aaede27bef9f4feccafe Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 15 Dec 2010 14:10:25 +0000 Subject: regulator: Allow modular build of mc13xxx-core Since the MFD core for this device and the regulator drivers for these devices can be built modular we should also support modular build of the shared code for the regulator drivers, otherwise we try to link built in code against modular code with unfortunate results. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 485a9bc..e1d9436 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -187,7 +187,7 @@ config REGULATOR_PCAP PCAP2 PMIC. config REGULATOR_MC13XXX_CORE - bool + tristate config REGULATOR_MC13783 tristate "Support regulators on Freescale MC13783 PMIC" diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c index 448e8f4..f53d31b 100644 --- a/drivers/regulator/mc13xxx-regulator-core.c +++ b/drivers/regulator/mc13xxx-regulator-core.c @@ -89,6 +89,7 @@ int mc13xxx_regulator_list_voltage(struct regulator_dev *rdev, return mc13xxx_regulators[id].voltages[selector]; } +EXPORT_SYMBOL_GPL(mc13xxx_regulator_list_voltage); int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, int min_uV, int max_uV) @@ -123,6 +124,7 @@ int mc13xxx_get_best_voltage_index(struct regulator_dev *rdev, } return bestindex; } +EXPORT_SYMBOL_GPL(mc13xxx_get_best_voltage_index); static int mc13xxx_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) @@ -185,6 +187,7 @@ struct regulator_ops mc13xxx_regulator_ops = { .set_voltage = mc13xxx_regulator_set_voltage, .get_voltage = mc13xxx_regulator_get_voltage, }; +EXPORT_SYMBOL_GPL(mc13xxx_regulator_ops); int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) @@ -202,6 +205,7 @@ int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, else return -EINVAL; } +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage); int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) { @@ -213,6 +217,7 @@ int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev) return mc13xxx_regulators[id].voltages[0]; } +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage); struct regulator_ops mc13xxx_fixed_regulator_ops = { .enable = mc13xxx_regulator_enable, @@ -222,11 +227,13 @@ struct regulator_ops mc13xxx_fixed_regulator_ops = { .set_voltage = mc13xxx_fixed_regulator_set_voltage, .get_voltage = mc13xxx_fixed_regulator_get_voltage, }; +EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops); int mc13xxx_sw_regulator_is_enabled(struct regulator_dev *rdev) { return 1; } +EXPORT_SYMBOL_GPL(mc13xxx_sw_regulator_is_enabled); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Yong Shen "); -- cgit v0.10.2 From c24516a1d674b1d9d847fd736feca444bc249b12 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:06:51 +0000 Subject: regulator: Convert WM835x to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 7e45b0d..1bcb22c 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -405,11 +405,10 @@ static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV, return 0; } -static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) +static int wm8350_dcdc_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, dcdc = rdev_get_id(rdev); - u16 val; switch (dcdc) { case WM8350_DCDC_1: @@ -431,8 +430,7 @@ static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev) } /* all DCDCs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; - return wm8350_dcdc_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK; } static int wm8350_dcdc_list_voltage(struct regulator_dev *rdev, @@ -807,11 +805,10 @@ static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV, return 0; } -static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) +static int wm8350_ldo_get_voltage_sel(struct regulator_dev *rdev) { struct wm8350 *wm8350 = rdev_get_drvdata(rdev); int volt_reg, ldo = rdev_get_id(rdev); - u16 val; switch (ldo) { case WM8350_LDO_1: @@ -831,8 +828,7 @@ static int wm8350_ldo_get_voltage(struct regulator_dev *rdev) } /* all LDOs have same mV bits */ - val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; - return wm8350_ldo_val_to_mvolts(val) * 1000; + return wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK; } static int wm8350_ldo_list_voltage(struct regulator_dev *rdev, @@ -1229,7 +1225,7 @@ static int wm8350_ldo_is_enabled(struct regulator_dev *rdev) static struct regulator_ops wm8350_dcdc_ops = { .set_voltage = wm8350_dcdc_set_voltage, - .get_voltage = wm8350_dcdc_get_voltage, + .get_voltage_sel = wm8350_dcdc_get_voltage_sel, .list_voltage = wm8350_dcdc_list_voltage, .enable = wm8350_dcdc_enable, .disable = wm8350_dcdc_disable, @@ -1253,7 +1249,7 @@ static struct regulator_ops wm8350_dcdc2_5_ops = { static struct regulator_ops wm8350_ldo_ops = { .set_voltage = wm8350_ldo_set_voltage, - .get_voltage = wm8350_ldo_get_voltage, + .get_voltage_sel = wm8350_ldo_get_voltage_sel, .list_voltage = wm8350_ldo_list_voltage, .enable = wm8350_ldo_enable, .disable = wm8350_ldo_disable, -- cgit v0.10.2 From d9f0f287179f76ec71a50a96d553dfd1dbb41711 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:07:06 +0000 Subject: regulator: Convert WM8994 to use get_voltage_sel() Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c index 1b162e6..594f88eb 100644 --- a/drivers/regulator/wm8994-regulator.c +++ b/drivers/regulator/wm8994-regulator.c @@ -86,7 +86,7 @@ static int wm8994_ldo1_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 2400000; } -static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo1_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -95,9 +95,7 @@ static int wm8994_ldo1_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; - - return wm8994_ldo1_list_voltage(rdev, val); + return (val & WM8994_LDO1_VSEL_MASK) >> WM8994_LDO1_VSEL_SHIFT; } static int wm8994_ldo1_set_voltage(struct regulator_dev *rdev, @@ -125,7 +123,7 @@ static struct regulator_ops wm8994_ldo1_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo1_list_voltage, - .get_voltage = wm8994_ldo1_get_voltage, + .get_voltage_sel = wm8994_ldo1_get_voltage_sel, .set_voltage = wm8994_ldo1_set_voltage, }; @@ -138,7 +136,7 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev, return (selector * 100000) + 900000; } -static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) +static int wm8994_ldo2_get_voltage_sel(struct regulator_dev *rdev) { struct wm8994_ldo *ldo = rdev_get_drvdata(rdev); int val; @@ -147,9 +145,7 @@ static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev) if (val < 0) return val; - val = (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; - - return wm8994_ldo2_list_voltage(rdev, val); + return (val & WM8994_LDO2_VSEL_MASK) >> WM8994_LDO2_VSEL_SHIFT; } static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev, @@ -177,7 +173,7 @@ static struct regulator_ops wm8994_ldo2_ops = { .enable_time = wm8994_ldo_enable_time, .list_voltage = wm8994_ldo2_list_voltage, - .get_voltage = wm8994_ldo2_get_voltage, + .get_voltage_sel = wm8994_ldo2_get_voltage_sel, .set_voltage = wm8994_ldo2_set_voltage, }; -- cgit v0.10.2 From 757902513019e6ee469791ff76f954b19ca8d036 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:25:50 +0000 Subject: regulator: Factor out voltage set operation into a separate function Push all the callers of the chip set_voltage() operation out into a single function to facilitiate future refactoring. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b362dbd..23c5f7c 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -83,6 +83,8 @@ static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); static void _notifier_call_chain(struct regulator_dev *rdev, unsigned long event, void *data); +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV); static const char *rdev_get_name(struct regulator_dev *rdev) { @@ -745,22 +747,19 @@ static int machine_constraints_voltage(struct regulator_dev *rdev, { struct regulator_ops *ops = rdev->desc->ops; int ret; - unsigned selector; /* do we need to apply the constraint voltage */ if (rdev->constraints->apply_uV && - rdev->constraints->min_uV == rdev->constraints->max_uV && - ops->set_voltage) { - ret = ops->set_voltage(rdev, - rdev->constraints->min_uV, - rdev->constraints->max_uV, - &selector); - if (ret < 0) { - rdev_err(rdev, "failed to apply %duV constraint\n", - rdev->constraints->min_uV); - rdev->constraints = NULL; - return ret; - } + rdev->constraints->min_uV == rdev->constraints->max_uV) { + ret = _regulator_do_set_voltage(rdev, + rdev->constraints->min_uV, + rdev->constraints->max_uV); + if (ret < 0) { + rdev_err(rdev, "failed to apply %duV constraint\n", + rdev->constraints->min_uV); + rdev->constraints = NULL; + return ret; + } } /* constrain machine-level voltage specs to fit @@ -1621,6 +1620,32 @@ int regulator_is_supported_voltage(struct regulator *regulator, return 0; } +static int _regulator_do_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + int ret; + unsigned int selector; + + trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); + + if (rdev->desc->ops->set_voltage) { + ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, + &selector); + + if (rdev->desc->ops->list_voltage) + selector = rdev->desc->ops->list_voltage(rdev, + selector); + else + selector = -1; + } else { + ret = -EINVAL; + } + + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + + return ret; +} + /** * regulator_set_voltage - set regulator output voltage * @regulator: regulator source @@ -1643,7 +1668,6 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret; - unsigned selector; mutex_lock(&rdev->mutex); @@ -1664,16 +1688,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) if (ret < 0) goto out; - trace_regulator_set_voltage(rdev_get_name(rdev), min_uV, max_uV); - - ret = rdev->desc->ops->set_voltage(rdev, min_uV, max_uV, &selector); - - if (rdev->desc->ops->list_voltage) - selector = rdev->desc->ops->list_voltage(rdev, selector); - else - selector = -1; - - trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); -- cgit v0.10.2 From e8eef82b2c652d031bee9dff9762325672f5a1e0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 12 Dec 2010 14:36:17 +0000 Subject: regulator: Provide a selector based set_voltage_sel() operation Many regulator drivers implement voltage setting by looping through a table of possible values, normally because the set of available voltages can't be mapped onto selectors with simple calcuation. Factor out these loops by providing a variant of set_voltage() which takes a selector rather than a voltage range as an argument and implementing a loop through the available selectors in the core. This is not going to be suitable for use with all devices as when the regulator voltage can be mapped onto selector values with a simple calculation the linear scan through the available values will be more expensive than just doing the calculation, especially for regulators that provide fine grained voltage control. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 23c5f7c..a0579f0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1637,6 +1637,32 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, selector); else selector = -1; + } else if (rdev->desc->ops->set_voltage_sel) { + int best_val = INT_MAX; + int i; + + selector = 0; + + /* Find the smallest voltage that falls within the specified + * range. + */ + for (i = 0; i < rdev->desc->n_voltages; i++) { + ret = rdev->desc->ops->list_voltage(rdev, i); + if (ret < 0) + continue; + + if (ret < best_val && ret >= min_uV && ret <= max_uV) { + best_val = ret; + selector = i; + } + } + + if (best_val != INT_MAX) { + ret = rdev->desc->ops->set_voltage_sel(rdev, selector); + selector = best_val; + } else { + ret = -EINVAL; + } } else { ret = -EINVAL; } @@ -1672,7 +1698,8 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) mutex_lock(&rdev->mutex); /* sanity check */ - if (!rdev->desc->ops->set_voltage) { + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { ret = -EINVAL; goto out; } @@ -2256,7 +2283,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; /* constraints need specific supporting methods */ - if (ops->set_voltage) { + if (ops->set_voltage || ops->set_voltage_sel) { status = device_create_file(dev, &dev_attr_min_microvolts); if (status < 0) return status; @@ -2354,12 +2381,18 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* Only one of each should be implemented */ WARN_ON(regulator_desc->ops->get_voltage && regulator_desc->ops->get_voltage_sel); + WARN_ON(regulator_desc->ops->set_voltage && + regulator_desc->ops->set_voltage_sel); /* If we're using selectors we must implement list_voltage. */ if (regulator_desc->ops->get_voltage_sel && !regulator_desc->ops->list_voltage) { return ERR_PTR(-EINVAL); } + if (regulator_desc->ops->set_voltage_sel && + !regulator_desc->ops->list_voltage) { + return ERR_PTR(-EINVAL); + } rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); if (rdev == NULL) diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index bf3e653..975ae06 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -42,6 +42,8 @@ enum regulator_status { * * @set_voltage: Set the voltage for the regulator within the range specified. * The driver should select the voltage closest to min_uV. + * @set_voltage_sel: Set the voltage for the regulator using the specified + * selector. * @get_voltage: Return the currently configured voltage for the regulator. * @get_voltage_sel: Return the currently configured voltage selector for the * regulator. @@ -83,6 +85,7 @@ struct regulator_ops { /* get/set regulator voltage */ int (*set_voltage) (struct regulator_dev *, int min_uV, int max_uV, unsigned *selector); + int (*set_voltage_sel) (struct regulator_dev *, unsigned selector); int (*get_voltage) (struct regulator_dev *); int (*get_voltage_sel) (struct regulator_dev *); -- cgit v0.10.2 From ded06a5270ddd6c3c3e25d9ddcaaaa4cb8385c2f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 13:59:10 +0000 Subject: regulator: Only notify voltage changes when they succeed Currently we notify a voltage change whenever we exit set_voltage(), even if the change failed for some reason (eg, a constraints issue). This shouldn't cause any substantial ill effects but is wasteful as listeners get notified on noops. Fix this by moving the notification into _do_set_voltage() and only notifying if we don't return an error. Reported-by: Saravana Kannan Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a0579f0..3d72cc8 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1667,6 +1667,10 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, ret = -EINVAL; } + if (ret == 0) + _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, + NULL); + trace_regulator_set_voltage_complete(rdev_get_name(rdev), selector); return ret; @@ -1718,7 +1722,6 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); out: - _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE, NULL); mutex_unlock(&rdev->mutex); return ret; } -- cgit v0.10.2 From 27315cf61fb813b3916cecfbfa6932dc9447f3f4 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:29:56 +0000 Subject: regulator: Staticise non-exported functions in mc13892 No point exposing functions that aren't used elsewhere to the global namespace and sparse warns about doing so. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index ca1d30a..16a0532 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -295,8 +295,8 @@ static struct mc13xxx_regulator mc13892_regulators[] = { MC13892_GPO_DEFINE(PWGT2SPI, POWERMISC, mc13892_pwgtdrv), }; -int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, - u32 val) +static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask, + u32 val) { struct mc13xxx *mc13892 = priv->mc13xxx; int ret; @@ -496,7 +496,7 @@ static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode) return ret; } -unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) +static unsigned int mc13892_vcam_get_mode(struct regulator_dev *rdev) { struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev); int ret, id = rdev_get_id(rdev); -- cgit v0.10.2 From 606a25628187ce863b48d43ca42bc0cbe8342de9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:49:36 +0000 Subject: regulator: Add API to re-apply voltage to hardware When cooperating with an external control source the regulator setup may be changed underneath the API. Currently consumers can just redo the regulator_set_voltage() to restore a previously set configuration but provide an explicit API for doing this as optimsations in the regulator_set_voltage() implementation will shortly prevent that. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 3d72cc8..a12cba3 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1727,6 +1727,53 @@ out: } EXPORT_SYMBOL_GPL(regulator_set_voltage); +/** + * regulator_sync_voltage - re-apply last regulator output voltage + * @regulator: regulator source + * + * Re-apply the last configured voltage. This is intended to be used + * where some external control source the consumer is cooperating with + * has caused the configured voltage to change. + */ +int regulator_sync_voltage(struct regulator *regulator) +{ + struct regulator_dev *rdev = regulator->rdev; + int ret, min_uV, max_uV; + + mutex_lock(&rdev->mutex); + + if (!rdev->desc->ops->set_voltage && + !rdev->desc->ops->set_voltage_sel) { + ret = -EINVAL; + goto out; + } + + /* This is only going to work if we've had a voltage configured. */ + if (!regulator->min_uV && !regulator->max_uV) { + ret = -EINVAL; + goto out; + } + + min_uV = regulator->min_uV; + max_uV = regulator->max_uV; + + /* This should be a paranoia check... */ + ret = regulator_check_voltage(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = regulator_check_consumers(rdev, &min_uV, &max_uV); + if (ret < 0) + goto out; + + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); + +out: + mutex_unlock(&rdev->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(regulator_sync_voltage); + static int _regulator_get_voltage(struct regulator_dev *rdev) { int sel; diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index ebd7472..7954f6b 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -154,6 +154,7 @@ int regulator_is_supported_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV); int regulator_get_voltage(struct regulator *regulator); +int regulator_sync_voltage(struct regulator *regulator); int regulator_set_current_limit(struct regulator *regulator, int min_uA, int max_uA); int regulator_get_current_limit(struct regulator *regulator); -- cgit v0.10.2 From 95a3c23ae620c1b4c499746e70f4034bdc067737 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Dec 2010 15:49:37 +0000 Subject: regulator: Optimise out noop voltage changes If a consumer sets the same voltage range as is currently configured for that consumer there's no need to run through setting the voltage again. This pattern may occur with some CPUfreq implementations where the same voltage range is used for multiple frequencies. Reported-by: Saravana Kannan Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index a12cba3..ab419f8 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1697,10 +1697,17 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; - int ret; + int ret = 0; mutex_lock(&rdev->mutex); + /* If we're setting the same range as last time the change + * should be a noop (some cpufreq implementations use the same + * voltage for multiple frequencies, for example). + */ + if (regulator->min_uV == min_uV && regulator->max_uV == max_uV) + goto out; + /* sanity check */ if (!rdev->desc->ops->set_voltage && !rdev->desc->ops->set_voltage_sel) { -- cgit v0.10.2 From 13ce29f80fe3f61d3865b90244b1d1430f553e9f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 17 Dec 2010 16:04:12 +0000 Subject: regulator: Clean up logging a bit The recent introduction of standard regulator API logging macros means that all our log messages have at least the function name in them and logging that the constraints are for the regulator API is probably a bit much. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index ab419f8..911b774 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -739,7 +739,7 @@ static void print_constraints(struct regulator_dev *rdev) if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY) count += sprintf(buf + count, "standby"); - rdev_info(rdev, "regulator: %s\n", buf); + rdev_info(rdev, "%s\n", buf); } static int machine_constraints_voltage(struct regulator_dev *rdev, -- cgit v0.10.2 From 21cf891a47ff5e7bd77fdc524a25072c447d56bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Dec 2010 23:30:07 +0000 Subject: regulator: Make regulator_has_full_constraints a bool It's a boolean value so use the type. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 911b774..6066a8f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -44,7 +44,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); -static int has_full_constraints; +static bool has_full_constraints; static bool board_wants_dummy_regulator; /* -- cgit v0.10.2 From 1130e5b3ff4a7f3f54a48d46e9d0d81b47765bd8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 21 Dec 2010 23:49:31 +0000 Subject: regulator: Add initial per-regulator debugfs support We only expose the use and open counts to userspace, providing a tiny bit of insight into what the API is up to. Signed-off-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6066a8f..9fa2095 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -47,6 +48,10 @@ static LIST_HEAD(regulator_map_list); static bool has_full_constraints; static bool board_wants_dummy_regulator; +#ifdef CONFIG_DEBUG_FS +static struct dentry *debugfs_root; +#endif + /* * struct regulator_map * @@ -2404,6 +2409,23 @@ static int add_regulator_attributes(struct regulator_dev *rdev) return status; } +static void rdev_init_debugfs(struct regulator_dev *rdev) +{ +#ifdef CONFIG_DEBUG_FS + rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root); + if (IS_ERR(rdev->debugfs) || !rdev->debugfs) { + rdev_warn(rdev, "Failed to create debugfs directory\n"); + rdev->debugfs = NULL; + return; + } + + debugfs_create_u32("use_count", 0444, rdev->debugfs, + &rdev->use_count); + debugfs_create_u32("open_count", 0444, rdev->debugfs, + &rdev->open_count); +#endif +} + /** * regulator_register - register regulator * @regulator_desc: regulator to register @@ -2548,6 +2570,8 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, } list_add(&rdev->list, ®ulator_list); + + rdev_init_debugfs(rdev); out: mutex_unlock(®ulator_list_mutex); return rdev; @@ -2580,6 +2604,9 @@ void regulator_unregister(struct regulator_dev *rdev) return; mutex_lock(®ulator_list_mutex); +#ifdef CONFIG_DEBUG_FS + debugfs_remove_recursive(rdev->debugfs); +#endif WARN_ON(rdev->open_count); unset_regulator_supplies(rdev); list_del(&rdev->list); @@ -2723,6 +2750,14 @@ static int __init regulator_init(void) ret = class_register(®ulator_class); +#ifdef CONFIG_DEBUG_FS + debugfs_root = debugfs_create_dir("regulator", NULL); + if (IS_ERR(debugfs_root) || !debugfs_root) { + pr_warn("regulator: Failed to create debugfs directory\n"); + debugfs_root = NULL; + } +#endif + regulator_dummy_init(); return ret; diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 975ae06..b8ed16a 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -175,9 +175,9 @@ struct regulator_desc { */ struct regulator_dev { struct regulator_desc *desc; - int use_count; - int open_count; int exclusive; + u32 use_count; + u32 open_count; /* lists we belong to */ struct list_head list; /* list of all regulators */ @@ -195,6 +195,10 @@ struct regulator_dev { struct regulator_dev *supply; /* for tree */ void *reg_data; /* regulator_dev data */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs; +#endif }; struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, -- cgit v0.10.2 From 923430cfee112c5f8223a313f5ec148a27dfed7f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 3 Jan 2011 23:57:38 +0800 Subject: regulator: Assign return value of mc13xxx_reg_rmw to ret Otherwise, we will not return error if write to MC13892_SWITCHERS5 failed. Signed-off-by: Axel Lin Acked-by: Yong Shen Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/mc13892-regulator.c b/drivers/regulator/mc13892-regulator.c index 16a0532..1b8f739 100644 --- a/drivers/regulator/mc13892-regulator.c +++ b/drivers/regulator/mc13892-regulator.c @@ -550,7 +550,7 @@ static int __devinit mc13892_regulator_probe(struct platform_device *pdev) if (ret) goto err_free; - mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, + ret = mc13xxx_reg_rmw(mc13892, MC13892_SWITCHERS5, MC13892_SWITCHERS5_SW3MODE_M | MC13892_SWITCHERS5_SW4MODE_M, MC13892_SWITCHERS5_SW3MODE_AUTO | -- cgit v0.10.2 From fa63bd4aa53aecc38956cbdd50f8ff9ed0d6d5ba Mon Sep 17 00:00:00 2001 From: roel kluin Date: Fri, 31 Dec 2010 16:26:47 +0100 Subject: regulator: missing index in PTR_ERR() in isl6271a_probe() The index is missing so the return is wrong. Signed-off-by: Roel Kluin Acked-by: Mark Brown Signed-off-by: Liam Girdwood diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index b5639e8..e4b3592 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -173,7 +173,7 @@ static int __devinit isl6271a_probe(struct i2c_client *i2c, init_data, pmic); if (IS_ERR(pmic->rdev[i])) { dev_err(&i2c->dev, "failed to register %s\n", id->name); - err = PTR_ERR(pmic->rdev); + err = PTR_ERR(pmic->rdev[i]); goto error; } } -- cgit v0.10.2