diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/88pm8607.c | 37 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 10 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/anatop-regulator.c | 41 | ||||
-rw-r--r-- | drivers/regulator/arizona-micsupp.c | 78 | ||||
-rw-r--r-- | drivers/regulator/as3711-regulator.c | 2 | ||||
-rw-r--r-- | drivers/regulator/core.c | 43 | ||||
-rw-r--r-- | drivers/regulator/da9052-regulator.c | 41 | ||||
-rw-r--r-- | drivers/regulator/da9055-regulator.c | 3 | ||||
-rw-r--r-- | drivers/regulator/gpio-regulator.c | 7 | ||||
-rw-r--r-- | drivers/regulator/lp3971.c | 22 | ||||
-rw-r--r-- | drivers/regulator/lp3972.c | 22 | ||||
-rw-r--r-- | drivers/regulator/lp872x.c | 36 | ||||
-rw-r--r-- | drivers/regulator/lp8755.c | 566 | ||||
-rw-r--r-- | drivers/regulator/lp8788-buck.c | 41 | ||||
-rw-r--r-- | drivers/regulator/lp8788-ldo.c | 133 | ||||
-rw-r--r-- | drivers/regulator/tps6586x-regulator.c | 54 |
17 files changed, 816 insertions, 321 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index 2b55711..a957e8c 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -30,8 +30,6 @@ struct pm8607_regulator_info { unsigned int *vol_table; unsigned int *vol_suspend; - int update_reg; - int update_bit; int slope_double; }; @@ -222,29 +220,6 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) -{ - struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); - uint8_t val; - int ret; - - val = (uint8_t)(selector << (ffs(rdev->desc->vsel_mask) - 1)); - - ret = pm860x_set_bits(info->i2c, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, val); - if (ret) - return ret; - switch (info->desc.id) { - case PM8607_ID_BUCK1: - case PM8607_ID_BUCK3: - ret = pm860x_set_bits(info->i2c, info->update_reg, - 1 << info->update_bit, - 1 << info->update_bit); - break; - } - return ret; -} - static int pm8606_preg_enable(struct regulator_dev *rdev) { struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); @@ -276,7 +251,7 @@ static int pm8606_preg_is_enabled(struct regulator_dev *rdev) static struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, - .set_voltage_sel = pm8607_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -313,11 +288,11 @@ static struct regulator_ops pm8606_preg_ops = { .n_voltages = ARRAY_SIZE(vreg##_table), \ .vsel_reg = PM8607_##vreg, \ .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \ + .apply_reg = PM8607_##ureg, \ + .apply_bit = (ubit), \ .enable_reg = PM8607_##ereg, \ .enable_mask = 1 << (ebit), \ }, \ - .update_reg = PM8607_##ureg, \ - .update_bit = (ubit), \ .slope_double = (0), \ .vol_table = (unsigned int *)&vreg##_table, \ .vol_suspend = (unsigned int *)&vreg##_suspend_table, \ @@ -343,9 +318,9 @@ static struct regulator_ops pm8606_preg_ops = { } static struct pm8607_regulator_info pm8607_regulator_info[] = { - PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0), - PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1), - PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2), + PM8607_DVC(BUCK1, GO, BIT(0), SUPPLIES_EN11, 0), + PM8607_DVC(BUCK2, GO, BIT(1), SUPPLIES_EN11, 1), + PM8607_DVC(BUCK3, GO, BIT(2), SUPPLIES_EN11, 2), PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3), PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4), diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 551a22b..a5d97ea 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -91,6 +91,7 @@ config REGULATOR_AAT2870 config REGULATOR_ARIZONA tristate "Wolfson Arizona class devices" depends on MFD_ARIZONA + depends on SND_SOC help Support for the regulators found on Wolfson Arizona class devices. @@ -277,6 +278,15 @@ config REGULATOR_LP872X help This driver supports LP8720/LP8725 PMIC +config REGULATOR_LP8755 + tristate "TI LP8755 High Performance PMU driver" + depends on I2C + select REGMAP_I2C + help + This driver supports LP8755 High Performance PMU driver. This + chip contains six step-down DC/DC converters which can support + 9 mode multiphase configuration. + config REGULATOR_LP8788 bool "TI LP8788 Power Regulators" depends on MFD_LP8788 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b802b0c..6e82503 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_LP872X) += lp872x.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-buck.o obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o +obj-$(CONFIG_REGULATOR_LP8755) += lp8755.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 8f39cac..0d4a8cc 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -31,12 +31,18 @@ #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> +#define LDO_RAMP_UP_UNIT_IN_CYCLES 64 /* 64 cycles per step */ +#define LDO_RAMP_UP_FREQ_IN_MHZ 24 /* cycle based on 24M OSC */ + struct anatop_regulator { const char *name; u32 control_reg; struct regmap *anatop; int vol_bit_shift; int vol_bit_width; + u32 delay_reg; + int delay_bit_shift; + int delay_bit_width; int min_bit_val; int min_voltage; int max_voltage; @@ -55,6 +61,32 @@ static int anatop_regmap_set_voltage_sel(struct regulator_dev *reg, return regulator_set_voltage_sel_regmap(reg, selector); } +static int anatop_regmap_set_voltage_time_sel(struct regulator_dev *reg, + unsigned int old_sel, + unsigned int new_sel) +{ + struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); + u32 val; + int ret = 0; + + /* check whether need to care about LDO ramp up speed */ + if (anatop_reg->delay_bit_width && new_sel > old_sel) { + /* + * the delay for LDO ramp up time is + * based on the register setting, we need + * to calculate how many steps LDO need to + * ramp up, and how much delay needed. (us) + */ + regmap_read(anatop_reg->anatop, anatop_reg->delay_reg, &val); + val = (val >> anatop_reg->delay_bit_shift) & + ((1 << anatop_reg->delay_bit_width) - 1); + ret = (new_sel - old_sel) * (LDO_RAMP_UP_UNIT_IN_CYCLES << + val) / LDO_RAMP_UP_FREQ_IN_MHZ + 1; + } + + return ret; +} + static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) { struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg); @@ -67,6 +99,7 @@ static int anatop_regmap_get_voltage_sel(struct regulator_dev *reg) static struct regulator_ops anatop_rops = { .set_voltage_sel = anatop_regmap_set_voltage_sel, + .set_voltage_time_sel = anatop_regmap_set_voltage_time_sel, .get_voltage_sel = anatop_regmap_get_voltage_sel, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, @@ -143,6 +176,14 @@ static int anatop_regulator_probe(struct platform_device *pdev) goto anatop_probe_end; } + /* read LDO ramp up setting, only for core reg */ + of_property_read_u32(np, "anatop-delay-reg-offset", + &sreg->delay_reg); + of_property_read_u32(np, "anatop-delay-bit-width", + &sreg->delay_bit_width); + of_property_read_u32(np, "anatop-delay-bit-shift", + &sreg->delay_bit_shift); + rdesc->n_voltages = (sreg->max_voltage - sreg->min_voltage) / 25000 + 1 + sreg->min_bit_val; rdesc->min_uV = sreg->min_voltage; diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index a6d040c..e87536b 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -21,6 +21,8 @@ #include <linux/regulator/machine.h> #include <linux/gpio.h> #include <linux/slab.h> +#include <linux/workqueue.h> +#include <sound/soc.h> #include <linux/mfd/arizona/core.h> #include <linux/mfd/arizona/pdata.h> @@ -34,6 +36,8 @@ struct arizona_micsupp { struct regulator_consumer_supply supply; struct regulator_init_data init_data; + + struct work_struct check_cp_work; }; static int arizona_micsupp_list_voltage(struct regulator_dev *rdev, @@ -72,9 +76,73 @@ static int arizona_micsupp_map_voltage(struct regulator_dev *rdev, return selector; } +static void arizona_micsupp_check_cp(struct work_struct *work) +{ + struct arizona_micsupp *micsupp = + container_of(work, struct arizona_micsupp, check_cp_work); + struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm; + struct arizona *arizona = micsupp->arizona; + struct regmap *regmap = arizona->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(regmap, ARIZONA_MIC_CHARGE_PUMP_1, ®); + if (ret != 0) { + dev_err(arizona->dev, "Failed to read CP state: %d\n", ret); + return; + } + + if (dapm) { + if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) == + ARIZONA_CPMIC_ENA) + snd_soc_dapm_force_enable_pin(dapm, "MICSUPP"); + else + snd_soc_dapm_disable_pin(dapm, "MICSUPP"); + + snd_soc_dapm_sync(dapm); + } +} + +static int arizona_micsupp_enable(struct regulator_dev *rdev) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_enable_regmap(rdev); + + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + +static int arizona_micsupp_disable(struct regulator_dev *rdev) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_disable_regmap(rdev); + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + +static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena) +{ + struct arizona_micsupp *micsupp = rdev_get_drvdata(rdev); + int ret; + + ret = regulator_set_bypass_regmap(rdev, ena); + if (ret == 0) + schedule_work(&micsupp->check_cp_work); + + return ret; +} + static struct regulator_ops arizona_micsupp_ops = { - .enable = regulator_enable_regmap, - .disable = regulator_disable_regmap, + .enable = arizona_micsupp_enable, + .disable = arizona_micsupp_disable, .is_enabled = regulator_is_enabled_regmap, .list_voltage = arizona_micsupp_list_voltage, @@ -84,7 +152,7 @@ static struct regulator_ops arizona_micsupp_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_bypass = regulator_get_bypass_regmap, - .set_bypass = regulator_set_bypass_regmap, + .set_bypass = arizona_micsupp_set_bypass, }; static const struct regulator_desc arizona_micsupp = { @@ -109,7 +177,8 @@ static const struct regulator_desc arizona_micsupp = { static const struct regulator_init_data arizona_micsupp_default = { .constraints = { .valid_ops_mask = REGULATOR_CHANGE_STATUS | - REGULATOR_CHANGE_VOLTAGE, + REGULATOR_CHANGE_VOLTAGE | + REGULATOR_CHANGE_BYPASS, .min_uV = 1700000, .max_uV = 3300000, }, @@ -131,6 +200,7 @@ static int arizona_micsupp_probe(struct platform_device *pdev) } micsupp->arizona = arizona; + INIT_WORK(&micsupp->check_cp_work, arizona_micsupp_check_cp); /* * Since the chip usually supplies itself we provide some diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index 2f1341d..f0ba8c4 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -303,7 +303,7 @@ static int as3711_regulator_probe(struct platform_device *pdev) reg_data = pdata ? pdata->init_data[id] : NULL; /* No need to register if there is no regulator data */ - if (!ri->desc.name) + if (!reg_data) continue; reg = ®s[id]; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 2785843..da9782b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -200,8 +200,8 @@ static int regulator_check_consumers(struct regulator_dev *rdev, } if (*min_uV > *max_uV) { - dev_err(regulator->dev, "Restricting voltage, %u-%uuV\n", - regulator->min_uV, regulator->max_uV); + rdev_err(rdev, "Restricting voltage, %u-%uuV\n", + *min_uV, *max_uV); return -EINVAL; } @@ -2080,10 +2080,20 @@ EXPORT_SYMBOL_GPL(regulator_get_voltage_sel_regmap); */ int regulator_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) { + int ret; + sel <<= ffs(rdev->desc->vsel_mask) - 1; - return regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, rdev->desc->vsel_mask, sel); + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage_sel_regmap); @@ -2229,8 +2239,11 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, best_val = rdev->desc->ops->list_voltage(rdev, ret); if (min_uV <= best_val && max_uV >= best_val) { selector = ret; - ret = rdev->desc->ops->set_voltage_sel(rdev, - ret); + if (old_selector == selector) + ret = 0; + else + ret = rdev->desc->ops->set_voltage_sel( + rdev, ret); } else { ret = -EINVAL; } @@ -2241,7 +2254,7 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev, /* Call set_voltage_time_sel if successfully obtained old_selector */ if (ret == 0 && _regulator_is_enabled(rdev) && old_selector >= 0 && - rdev->desc->ops->set_voltage_time_sel) { + old_selector != selector && rdev->desc->ops->set_voltage_time_sel) { delay = rdev->desc->ops->set_voltage_time_sel(rdev, old_selector, selector); @@ -2294,6 +2307,7 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { struct regulator_dev *rdev = regulator->rdev; int ret = 0; + int old_min_uV, old_max_uV; mutex_lock(&rdev->mutex); @@ -2315,18 +2329,29 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) ret = regulator_check_voltage(rdev, &min_uV, &max_uV); if (ret < 0) goto out; + + /* restore original values in case of error */ + old_min_uV = regulator->min_uV; + old_max_uV = regulator->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; + goto out2; ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); - + if (ret < 0) + goto out2; + out: mutex_unlock(&rdev->mutex); return ret; +out2: + regulator->min_uV = old_min_uV; + regulator->max_uV = old_max_uV; + mutex_unlock(&rdev->mutex); + return ret; } EXPORT_SYMBOL_GPL(regulator_set_voltage); @@ -3208,7 +3233,7 @@ static int add_regulator_attributes(struct regulator_dev *rdev) if (status < 0) return status; } - if (ops->is_enabled) { + if (rdev->ena_gpio || ops->is_enabled) { status = device_create_file(dev, &dev_attr_state); if (status < 0) return status; diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c index d096309..c6d8651 100644 --- a/drivers/regulator/da9052-regulator.c +++ b/drivers/regulator/da9052-regulator.c @@ -70,7 +70,6 @@ struct da9052_regulator_info { int step_uV; int min_uV; int max_uV; - unsigned char activate_bit; }; struct da9052_regulator { @@ -210,36 +209,6 @@ static int da9052_map_voltage(struct regulator_dev *rdev, return sel; } -static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned int selector) -{ - struct da9052_regulator *regulator = rdev_get_drvdata(rdev); - struct da9052_regulator_info *info = regulator->info; - int id = rdev_get_id(rdev); - int ret; - - ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, selector); - if (ret < 0) - return ret; - - /* Some LDOs and DCDCs are DVC controlled which requires enabling of - * the activate bit to implment the changes on the output. - */ - switch (id) { - case DA9052_ID_BUCK1: - case DA9052_ID_BUCK2: - case DA9052_ID_BUCK3: - case DA9052_ID_LDO2: - case DA9052_ID_LDO3: - ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, - info->activate_bit, info->activate_bit); - break; - } - - return ret; -} - static struct regulator_ops da9052_dcdc_ops = { .get_current_limit = da9052_dcdc_get_current_limit, .set_current_limit = da9052_dcdc_set_current_limit, @@ -247,7 +216,7 @@ static struct regulator_ops da9052_dcdc_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -257,7 +226,7 @@ static struct regulator_ops da9052_ldo_ops = { .list_voltage = da9052_list_voltage, .map_voltage = da9052_map_voltage, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = da9052_regulator_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -274,13 +243,14 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ + .apply_reg = DA9052_SUPPLY_REG, \ + .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .activate_bit = (abits),\ } #define DA9052_DCDC(_id, step, min, max, sbits, ebits, abits) \ @@ -294,13 +264,14 @@ static struct regulator_ops da9052_ldo_ops = { .owner = THIS_MODULE,\ .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .vsel_mask = (1 << (sbits)) - 1,\ + .apply_reg = DA9052_SUPPLY_REG, \ + .apply_bit = (abits), \ .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ .enable_mask = 1 << (ebits),\ },\ .min_uV = (min) * 1000,\ .max_uV = (max) * 1000,\ .step_uV = (step) * 1000,\ - .activate_bit = (abits),\ } static struct da9052_regulator_info da9052_regulator_info[] = { diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 1a05ac6..3022109 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -58,7 +58,6 @@ struct da9055_volt_reg { int reg_b; int sl_shift; int v_mask; - int v_shift; }; struct da9055_mode_reg { @@ -388,7 +387,6 @@ static struct regulator_ops da9055_ldo_ops = { .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ .sl_shift = 7,\ .v_mask = (1 << (vbits)) - 1,\ - .v_shift = (vbits),\ },\ } @@ -417,7 +415,6 @@ static struct regulator_ops da9055_ldo_ops = { .reg_b = DA9055_REG_VBCORE_B + DA9055_ID_##_id, \ .sl_shift = 7,\ .v_mask = (1 << (vbits)) - 1,\ - .v_shift = (vbits),\ },\ .mode = {\ .reg = DA9055_REG_BCORE_MODE,\ diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c index bae681c..9d39eb4 100644 --- a/drivers/regulator/gpio-regulator.c +++ b/drivers/regulator/gpio-regulator.c @@ -132,7 +132,7 @@ static struct regulator_ops gpio_regulator_voltage_ops = { .list_voltage = gpio_regulator_list_voltage, }; -struct gpio_regulator_config * +static struct gpio_regulator_config * of_get_gpio_regulator_config(struct device *dev, struct device_node *np) { struct gpio_regulator_config *config; @@ -163,10 +163,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np) config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0); /* Fetch GPIOs. */ - for (i = 0; ; i++) - if (of_get_named_gpio(np, "gpios", i) < 0) - break; - config->nr_gpios = i; + config->nr_gpios = of_gpio_count(np); config->gpios = devm_kzalloc(dev, sizeof(struct gpio) * config->nr_gpios, diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 5f68ff1..9cb2c0f 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -73,8 +73,6 @@ static const unsigned int buck_voltage_map[] = { }; #define BUCK_TARGET_VOL_MASK 0x3f -#define BUCK_TARGET_VOL_MIN_IDX 0x01 -#define BUCK_TARGET_VOL_MAX_IDX 0x19 #define LP3971_BUCK_RAMP_REG(x) (buck_base_addr[x]+2) @@ -140,7 +138,7 @@ static int lp3971_ldo_disable(struct regulator_dev *dev) return lp3971_set_bits(lp3971, LP3971_LDO_ENABLE_REG, mask, 0); } -static int lp3971_ldo_get_voltage(struct regulator_dev *dev) +static int lp3971_ldo_get_voltage_sel(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3971_LDO1; @@ -149,7 +147,7 @@ static int lp3971_ldo_get_voltage(struct regulator_dev *dev) reg = lp3971_reg_read(lp3971, LP3971_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LDO_VOL_CONTR_SHIFT(ldo)) & LDO_VOL_CONTR_MASK; - return dev->desc->volt_table[val]; + return val; } static int lp3971_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -168,7 +166,7 @@ static struct regulator_ops lp3971_ldo_ops = { .is_enabled = lp3971_ldo_is_enabled, .enable = lp3971_ldo_enable, .disable = lp3971_ldo_disable, - .get_voltage = lp3971_ldo_get_voltage, + .get_voltage_sel = lp3971_ldo_get_voltage_sel, .set_voltage_sel = lp3971_ldo_set_voltage_sel, }; @@ -201,24 +199,16 @@ static int lp3971_dcdc_disable(struct regulator_dev *dev) return lp3971_set_bits(lp3971, LP3971_BUCK_VOL_ENABLE_REG, mask, 0); } -static int lp3971_dcdc_get_voltage(struct regulator_dev *dev) +static int lp3971_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct lp3971 *lp3971 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3971_DCDC1; u16 reg; - int val; reg = lp3971_reg_read(lp3971, LP3971_BUCK_TARGET_VOL1_REG(buck)); reg &= BUCK_TARGET_VOL_MASK; - if (reg <= BUCK_TARGET_VOL_MAX_IDX) - val = buck_voltage_map[reg]; - else { - val = 0; - dev_warn(&dev->dev, "chip reported incorrect voltage value.\n"); - } - - return val; + return reg; } static int lp3971_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -249,7 +239,7 @@ static struct regulator_ops lp3971_dcdc_ops = { .is_enabled = lp3971_dcdc_is_enabled, .enable = lp3971_dcdc_enable, .disable = lp3971_dcdc_disable, - .get_voltage = lp3971_dcdc_get_voltage, + .get_voltage_sel = lp3971_dcdc_get_voltage_sel, .set_voltage_sel = lp3971_dcdc_set_voltage_sel, }; diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index 69c42c3..0baabcf 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -165,8 +165,6 @@ static const int buck_base_addr[] = { #define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) #define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) #define LP3972_BUCK_VOL_MASK 0x1f -#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00) -#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f) static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, u16 *dest) @@ -257,7 +255,7 @@ static int lp3972_ldo_disable(struct regulator_dev *dev) mask, 0); } -static int lp3972_ldo_get_voltage(struct regulator_dev *dev) +static int lp3972_ldo_get_voltage_sel(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int ldo = rdev_get_id(dev) - LP3972_LDO1; @@ -267,7 +265,7 @@ static int lp3972_ldo_get_voltage(struct regulator_dev *dev) reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; - return dev->desc->volt_table[val]; + return val; } static int lp3972_ldo_set_voltage_sel(struct regulator_dev *dev, @@ -314,7 +312,7 @@ static struct regulator_ops lp3972_ldo_ops = { .is_enabled = lp3972_ldo_is_enabled, .enable = lp3972_ldo_enable, .disable = lp3972_ldo_disable, - .get_voltage = lp3972_ldo_get_voltage, + .get_voltage_sel = lp3972_ldo_get_voltage_sel, .set_voltage_sel = lp3972_ldo_set_voltage_sel, }; @@ -353,24 +351,16 @@ static int lp3972_dcdc_disable(struct regulator_dev *dev) return val; } -static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) +static int lp3972_dcdc_get_voltage_sel(struct regulator_dev *dev) { struct lp3972 *lp3972 = rdev_get_drvdata(dev); int buck = rdev_get_id(dev) - LP3972_DCDC1; u16 reg; - int val; reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); reg &= LP3972_BUCK_VOL_MASK; - if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck)) - val = dev->desc->volt_table[reg]; - else { - val = 0; - dev_warn(&dev->dev, "chip reported incorrect voltage value." - " reg = %d\n", reg); - } - return val; + return reg; } static int lp3972_dcdc_set_voltage_sel(struct regulator_dev *dev, @@ -402,7 +392,7 @@ static struct regulator_ops lp3972_dcdc_ops = { .is_enabled = lp3972_dcdc_is_enabled, .enable = lp3972_dcdc_enable, .disable = lp3972_dcdc_disable, - .get_voltage = lp3972_dcdc_get_voltage, + .get_voltage_sel = lp3972_dcdc_get_voltage_sel, .set_voltage_sel = lp3972_dcdc_set_voltage_sel, }; diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 9289ead..8e3c7ae 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -181,20 +181,6 @@ static inline int lp872x_update_bits(struct lp872x *lp, u8 addr, return regmap_update_bits(lp->regmap, addr, mask, data); } -static int _rdev_to_offset(struct regulator_dev *rdev) -{ - enum lp872x_regulator_id id = rdev_get_id(rdev); - - switch (id) { - case LP8720_ID_LDO1 ... LP8720_ID_BUCK: - return id; - case LP8725_ID_LDO1 ... LP8725_ID_BUCK2: - return id - LP8725_ID_BASE; - default: - return -EINVAL; - } -} - static int lp872x_get_timestep_usec(struct lp872x *lp) { enum lp872x_id chip = lp->chipid; @@ -234,28 +220,20 @@ static int lp872x_get_timestep_usec(struct lp872x *lp) static int lp872x_regulator_enable_time(struct regulator_dev *rdev) { struct lp872x *lp = rdev_get_drvdata(rdev); - enum lp872x_regulator_id regulator = rdev_get_id(rdev); + enum lp872x_regulator_id rid = rdev_get_id(rdev); int time_step_us = lp872x_get_timestep_usec(lp); - int ret, offset; + int ret; u8 addr, val; if (time_step_us < 0) return -EINVAL; - switch (regulator) { - case LP8720_ID_LDO1 ... LP8720_ID_LDO5: - case LP8725_ID_LDO1 ... LP8725_ID_LILO2: - offset = _rdev_to_offset(rdev); - if (offset < 0) - return -EINVAL; - - addr = LP872X_LDO1_VOUT + offset; - break; - case LP8720_ID_BUCK: - addr = LP8720_BUCK_VOUT1; + switch (rid) { + case LP8720_ID_LDO1 ... LP8720_ID_BUCK: + addr = LP872X_LDO1_VOUT + rid; break; - case LP8725_ID_BUCK1: - addr = LP8725_BUCK1_VOUT1; + case LP8725_ID_LDO1 ... LP8725_ID_BUCK1: + addr = LP872X_LDO1_VOUT + rid - LP8725_ID_BASE; break; case LP8725_ID_BUCK2: addr = LP8725_BUCK2_VOUT1; diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c new file mode 100644 index 0000000..f0f6ea0 --- /dev/null +++ b/drivers/regulator/lp8755.c @@ -0,0 +1,566 @@ +/* + * LP8755 High Performance Power Management Unit : System Interface Driver + * (based on rev. 0.26) + * Copyright 2012 Texas Instruments + * + * Author: Daniel(Geon Si) Jeong <daniel.jeong@ti.com> + * + * 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 <linux/module.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/delay.h> +#include <linux/uaccess.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/platform_data/lp8755.h> + +#define LP8755_REG_BUCK0 0x00 +#define LP8755_REG_BUCK1 0x03 +#define LP8755_REG_BUCK2 0x04 +#define LP8755_REG_BUCK3 0x01 +#define LP8755_REG_BUCK4 0x05 +#define LP8755_REG_BUCK5 0x02 +#define LP8755_REG_MAX 0xFF + +#define LP8755_BUCK_EN_M BIT(7) +#define LP8755_BUCK_LINEAR_OUT_MAX 0x76 +#define LP8755_BUCK_VOUT_M 0x7F + +struct lp8755_mphase { + int nreg; + int buck_num[LP8755_BUCK_MAX]; +}; + +struct lp8755_chip { + struct device *dev; + struct regmap *regmap; + struct lp8755_platform_data *pdata; + + int irq; + unsigned int irqmask; + + int mphase; + struct regulator_dev *rdev[LP8755_BUCK_MAX]; +}; + +/** + *lp8755_read : read a single register value from lp8755. + *@pchip : device to read from + *@reg : register to read from + *@val : pointer to store read value + */ +static int lp8755_read(struct lp8755_chip *pchip, unsigned int reg, + unsigned int *val) +{ + return regmap_read(pchip->regmap, reg, val); +} + +/** + *lp8755_write : write a single register value to lp8755. + *@pchip : device to write to + *@reg : register to write to + *@val : value to be written + */ +static int lp8755_write(struct lp8755_chip *pchip, unsigned int reg, + unsigned int val) +{ + return regmap_write(pchip->regmap, reg, val); +} + +/** + *lp8755_update_bits : set the values of bit fields in lp8755 register. + *@pchip : device to read from + *@reg : register to update + *@mask : bitmask to be changed + *@val : value for bitmask + */ +static int lp8755_update_bits(struct lp8755_chip *pchip, unsigned int reg, + unsigned int mask, unsigned int val) +{ + return regmap_update_bits(pchip->regmap, reg, mask, val); +} + +static int lp8755_buck_enable_time(struct regulator_dev *rdev) +{ + int ret; + unsigned int regval; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + ret = lp8755_read(pchip, 0x12 + id, ®val); + if (ret < 0) { + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; + } + return (regval & 0xff) * 100; +} + +static int lp8755_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + int ret; + unsigned int regbval = 0x0; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + switch (mode) { + case REGULATOR_MODE_FAST: + /* forced pwm mode */ + regbval = (0x01 << id); + break; + case REGULATOR_MODE_NORMAL: + /* enable automatic pwm/pfm mode */ + ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x00); + if (ret < 0) + goto err_i2c; + break; + case REGULATOR_MODE_IDLE: + /* enable automatic pwm/pfm/lppfm mode */ + ret = lp8755_update_bits(pchip, 0x08 + id, 0x20, 0x20); + if (ret < 0) + goto err_i2c; + + ret = lp8755_update_bits(pchip, 0x10, 0x01, 0x01); + if (ret < 0) + goto err_i2c; + break; + default: + dev_err(pchip->dev, "Not supported buck mode %s\n", __func__); + /* forced pwm mode */ + regbval = (0x01 << id); + } + + ret = lp8755_update_bits(pchip, 0x06, 0x01 << id, regbval); + if (ret < 0) + goto err_i2c; + return ret; +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static unsigned int lp8755_buck_get_mode(struct regulator_dev *rdev) +{ + int ret; + unsigned int regval; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + ret = lp8755_read(pchip, 0x06, ®val); + if (ret < 0) + goto err_i2c; + + /* mode fast means forced pwm mode */ + if (regval & (0x01 << id)) + return REGULATOR_MODE_FAST; + + ret = lp8755_read(pchip, 0x08 + id, ®val); + if (ret < 0) + goto err_i2c; + + /* mode idle means automatic pwm/pfm/lppfm mode */ + if (regval & 0x20) + return REGULATOR_MODE_IDLE; + + /* mode normal means automatic pwm/pfm mode */ + return REGULATOR_MODE_NORMAL; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return 0; +} + +static int lp8755_buck_set_ramp(struct regulator_dev *rdev, int ramp) +{ + int ret; + unsigned int regval = 0x00; + enum lp8755_bucks id = rdev_get_id(rdev); + struct lp8755_chip *pchip = rdev_get_drvdata(rdev); + + /* uV/us */ + switch (ramp) { + case 0 ... 230: + regval = 0x07; + break; + case 231 ... 470: + regval = 0x06; + break; + case 471 ... 940: + regval = 0x05; + break; + case 941 ... 1900: + regval = 0x04; + break; + case 1901 ... 3800: + regval = 0x03; + break; + case 3801 ... 7500: + regval = 0x02; + break; + case 7501 ... 15000: + regval = 0x01; + break; + case 15001 ... 30000: + regval = 0x00; + break; + default: + dev_err(pchip->dev, + "Not supported ramp value %d %s\n", ramp, __func__); + return -EINVAL; + } + + ret = lp8755_update_bits(pchip, 0x07 + id, 0x07, regval); + if (ret < 0) + goto err_i2c; + return ret; +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static struct regulator_ops lp8755_buck_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .enable_time = lp8755_buck_enable_time, + .set_mode = lp8755_buck_set_mode, + .get_mode = lp8755_buck_get_mode, + .set_ramp_delay = lp8755_buck_set_ramp, +}; + +#define lp8755_rail(_id) "lp8755_buck"#_id +#define lp8755_buck_init(_id)\ +{\ + .constraints = {\ + .name = lp8755_rail(_id),\ + .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,\ + .min_uV = 500000,\ + .max_uV = 1675000,\ + },\ +} + +static struct regulator_init_data lp8755_reg_default[LP8755_BUCK_MAX] = { + [LP8755_BUCK0] = lp8755_buck_init(0), + [LP8755_BUCK1] = lp8755_buck_init(1), + [LP8755_BUCK2] = lp8755_buck_init(2), + [LP8755_BUCK3] = lp8755_buck_init(3), + [LP8755_BUCK4] = lp8755_buck_init(4), + [LP8755_BUCK5] = lp8755_buck_init(5), +}; + +static const struct lp8755_mphase mphase_buck[MPHASE_CONF_MAX] = { + { 3, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK5 } }, + { 6, { LP8755_BUCK0, LP8755_BUCK1, LP8755_BUCK2, LP8755_BUCK3, + LP8755_BUCK4, LP8755_BUCK5 } }, + { 5, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK4, + LP8755_BUCK5} }, + { 4, { LP8755_BUCK0, LP8755_BUCK3, LP8755_BUCK4, LP8755_BUCK5} }, + { 3, { LP8755_BUCK0, LP8755_BUCK4, LP8755_BUCK5} }, + { 2, { LP8755_BUCK0, LP8755_BUCK5} }, + { 1, { LP8755_BUCK0} }, + { 2, { LP8755_BUCK0, LP8755_BUCK3} }, + { 4, { LP8755_BUCK0, LP8755_BUCK2, LP8755_BUCK3, LP8755_BUCK5} }, +}; + +static int lp8755_init_data(struct lp8755_chip *pchip) +{ + unsigned int regval; + int ret, icnt, buck_num; + struct lp8755_platform_data *pdata = pchip->pdata; + + /* read back muti-phase configuration */ + ret = lp8755_read(pchip, 0x3D, ®val); + if (ret < 0) + goto out_i2c_error; + pchip->mphase = regval & 0x0F; + + /* set default data based on multi-phase config */ + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { + buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; + pdata->buck_data[buck_num] = &lp8755_reg_default[buck_num]; + } + return ret; + +out_i2c_error: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +#define lp8755_buck_desc(_id)\ +{\ + .name = lp8755_rail(_id),\ + .id = LP8755_BUCK##_id,\ + .ops = &lp8755_buck_ops,\ + .n_voltages = LP8755_BUCK_LINEAR_OUT_MAX+1,\ + .uV_step = 10000,\ + .min_uV = 500000,\ + .type = REGULATOR_VOLTAGE,\ + .owner = THIS_MODULE,\ + .enable_reg = LP8755_REG_BUCK##_id,\ + .enable_mask = LP8755_BUCK_EN_M,\ + .vsel_reg = LP8755_REG_BUCK##_id,\ + .vsel_mask = LP8755_BUCK_VOUT_M,\ +} + +static struct regulator_desc lp8755_regulators[] = { + lp8755_buck_desc(0), + lp8755_buck_desc(1), + lp8755_buck_desc(2), + lp8755_buck_desc(3), + lp8755_buck_desc(4), + lp8755_buck_desc(5), +}; + +static int lp8755_regulator_init(struct lp8755_chip *pchip) +{ + int ret, icnt, buck_num; + struct lp8755_platform_data *pdata = pchip->pdata; + struct regulator_config rconfig = { }; + + rconfig.regmap = pchip->regmap; + rconfig.dev = pchip->dev; + rconfig.driver_data = pchip; + + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) { + buck_num = mphase_buck[pchip->mphase].buck_num[icnt]; + rconfig.init_data = pdata->buck_data[buck_num]; + rconfig.of_node = pchip->dev->of_node; + pchip->rdev[buck_num] = + regulator_register(&lp8755_regulators[buck_num], &rconfig); + if (IS_ERR(pchip->rdev[buck_num])) { + ret = PTR_ERR(pchip->rdev[buck_num]); + pchip->rdev[buck_num] = NULL; + dev_err(pchip->dev, "regulator init failed: buck %d\n", + buck_num); + goto err_buck; + } + } + + return 0; + +err_buck: + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + regulator_unregister(pchip->rdev[icnt]); + return ret; +} + +static irqreturn_t lp8755_irq_handler(int irq, void *data) +{ + int ret, icnt; + unsigned int flag0, flag1; + struct lp8755_chip *pchip = data; + + /* read flag0 register */ + ret = lp8755_read(pchip, 0x0D, &flag0); + if (ret < 0) + goto err_i2c; + /* clear flag register to pull up int. pin */ + ret = lp8755_write(pchip, 0x0D, 0x00); + if (ret < 0) + goto err_i2c; + + /* sent power fault detection event to specific regulator */ + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if ((flag0 & (0x4 << icnt)) + && (pchip->irqmask & (0x04 << icnt)) + && (pchip->rdev[icnt] != NULL)) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_PWR_FAULT, + NULL); + + /* read flag1 register */ + ret = lp8755_read(pchip, 0x0E, &flag1); + if (ret < 0) + goto err_i2c; + /* clear flag register to pull up int. pin */ + ret = lp8755_write(pchip, 0x0E, 0x00); + if (ret < 0) + goto err_i2c; + + /* send OCP event to all regualtor devices */ + if ((flag1 & 0x01) && (pchip->irqmask & 0x01)) + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if (pchip->rdev[icnt] != NULL) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_OCP, + NULL); + + /* send OVP event to all regualtor devices */ + if ((flag1 & 0x02) && (pchip->irqmask & 0x02)) + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + if (pchip->rdev[icnt] != NULL) + regulator_notifier_call_chain(pchip->rdev[icnt], + LP8755_EVENT_OVP, + NULL); + return IRQ_HANDLED; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return IRQ_NONE; +} + +static int lp8755_int_config(struct lp8755_chip *pchip) +{ + int ret; + unsigned int regval; + + if (pchip->irq == 0) { + dev_warn(pchip->dev, "not use interrupt : %s\n", __func__); + return 0; + } + + ret = lp8755_read(pchip, 0x0F, ®val); + if (ret < 0) + goto err_i2c; + pchip->irqmask = regval; + ret = request_threaded_irq(pchip->irq, NULL, lp8755_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "lp8755-irq", pchip); + if (ret) + return ret; + + return ret; + +err_i2c: + dev_err(pchip->dev, "i2c acceess error %s\n", __func__); + return ret; +} + +static const struct regmap_config lp8755_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = LP8755_REG_MAX, +}; + +static int lp8755_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret, icnt; + struct lp8755_chip *pchip; + struct lp8755_platform_data *pdata = client->dev.platform_data; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "i2c functionality check fail.\n"); + return -EOPNOTSUPP; + } + + pchip = devm_kzalloc(&client->dev, + sizeof(struct lp8755_chip), GFP_KERNEL); + if (!pchip) + return -ENOMEM; + + pchip->dev = &client->dev; + pchip->regmap = devm_regmap_init_i2c(client, &lp8755_regmap); + if (IS_ERR(pchip->regmap)) { + ret = PTR_ERR(pchip->regmap); + dev_err(&client->dev, "fail to allocate regmap %d\n", ret); + return ret; + } + i2c_set_clientdata(client, pchip); + + if (pdata != NULL) { + pchip->pdata = pdata; + pchip->mphase = pdata->mphase; + } else { + pchip->pdata = devm_kzalloc(pchip->dev, + sizeof(struct lp8755_platform_data), + GFP_KERNEL); + if (!pchip->pdata) + return -ENOMEM; + ret = lp8755_init_data(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to initialize chip\n"); + return ret; + } + } + + ret = lp8755_regulator_init(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to initialize regulators\n"); + goto err_regulator; + } + + pchip->irq = client->irq; + ret = lp8755_int_config(pchip); + if (ret < 0) { + dev_err(&client->dev, "fail to irq config\n"); + goto err_irq; + } + + return ret; + +err_irq: + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) + regulator_unregister(pchip->rdev[icnt]); + +err_regulator: + /* output disable */ + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + lp8755_write(pchip, icnt, 0x00); + + return ret; +} + +static int lp8755_remove(struct i2c_client *client) +{ + int icnt; + struct lp8755_chip *pchip = i2c_get_clientdata(client); + + for (icnt = 0; icnt < mphase_buck[pchip->mphase].nreg; icnt++) + regulator_unregister(pchip->rdev[icnt]); + + for (icnt = 0; icnt < LP8755_BUCK_MAX; icnt++) + lp8755_write(pchip, icnt, 0x00); + + if (pchip->irq != 0) + free_irq(pchip->irq, pchip); + + return 0; +} + +static const struct i2c_device_id lp8755_id[] = { + {LP8755_NAME, 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, lp8755_id); + +static struct i2c_driver lp8755_i2c_driver = { + .driver = { + .name = LP8755_NAME, + }, + .probe = lp8755_probe, + .remove = lp8755_remove, + .id_table = lp8755_id, +}; + +static int __init lp8755_init(void) +{ + return i2c_add_driver(&lp8755_i2c_driver); +} + +subsys_initcall(lp8755_init); + +static void __exit lp8755_exit(void) +{ + i2c_del_driver(&lp8755_i2c_driver); +} + +module_exit(lp8755_exit); + +MODULE_DESCRIPTION("Texas Instruments lp8755 driver"); +MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/lp8788-buck.c b/drivers/regulator/lp8788-buck.c index aef3f2b..97891a7 100644 --- a/drivers/regulator/lp8788-buck.c +++ b/drivers/regulator/lp8788-buck.c @@ -103,16 +103,6 @@ static const int lp8788_buck_vtbl[] = { 1950000, 2000000, }; -static const u8 buck1_vout_addr[] = { - LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1, - LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3, -}; - -static const u8 buck2_vout_addr[] = { - LP8788_BUCK2_VOUT0, LP8788_BUCK2_VOUT1, - LP8788_BUCK2_VOUT2, LP8788_BUCK2_VOUT3, -}; - static void lp8788_buck1_set_dvs(struct lp8788_buck *buck) { struct lp8788_buck1_dvs *dvs = (struct lp8788_buck1_dvs *)buck->dvs; @@ -235,7 +225,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); idx = (val & LP8788_BUCK1_DVS_M) >> LP8788_BUCK1_DVS_S; } - addr = buck1_vout_addr[idx]; + addr = LP8788_BUCK1_VOUT0 + idx; break; case BUCK2: if (mode == EXTPIN) { @@ -258,7 +248,7 @@ static u8 lp8788_select_buck_vout_addr(struct lp8788_buck *buck, lp8788_read_byte(buck->lp, LP8788_BUCK_DVS_SEL, &val); idx = (val & LP8788_BUCK2_DVS_M) >> LP8788_BUCK2_DVS_S; } - addr = buck2_vout_addr[idx]; + addr = LP8788_BUCK2_VOUT0 + idx; break; default: goto err; @@ -429,7 +419,8 @@ static struct regulator_desc lp8788_buck_desc[] = { }, }; -static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, +static int lp8788_dvs_gpio_request(struct platform_device *pdev, + struct lp8788_buck *buck, enum lp8788_buck_id id) { struct lp8788_platform_data *pdata = buck->lp->pdata; @@ -440,7 +431,7 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, switch (id) { case BUCK1: gpio = pdata->buck1_dvs->gpio; - ret = devm_gpio_request_one(buck->lp->dev, gpio, DVS_LOW, + ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW, b1_name); if (ret) return ret; @@ -448,9 +439,9 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, buck->dvs = pdata->buck1_dvs; break; case BUCK2: - for (i = 0 ; i < LP8788_NUM_BUCK2_DVS ; i++) { + for (i = 0; i < LP8788_NUM_BUCK2_DVS; i++) { gpio = pdata->buck2_dvs->gpio[i]; - ret = devm_gpio_request_one(buck->lp->dev, gpio, + ret = devm_gpio_request_one(&pdev->dev, gpio, DVS_LOW, b2_name[i]); if (ret) return ret; @@ -464,7 +455,8 @@ static int lp8788_dvs_gpio_request(struct lp8788_buck *buck, return 0; } -static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) +static int lp8788_init_dvs(struct platform_device *pdev, + struct lp8788_buck *buck, enum lp8788_buck_id id) { struct lp8788_platform_data *pdata = buck->lp->pdata; u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M }; @@ -472,7 +464,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C }; /* no dvs for buck3, 4 */ - if (id == BUCK3 || id == BUCK4) + if (id > BUCK2) return 0; /* no dvs platform data, then dvs will be selected by I2C registers */ @@ -483,7 +475,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id) (id == BUCK2 && !pdata->buck2_dvs)) goto set_default_dvs_mode; - if (lp8788_dvs_gpio_request(buck, id)) + if (lp8788_dvs_gpio_request(pdev, buck, id)) goto set_default_dvs_mode; return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id], @@ -503,17 +495,20 @@ static int lp8788_buck_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - buck = devm_kzalloc(lp->dev, sizeof(struct lp8788_buck), GFP_KERNEL); + if (id >= LP8788_NUM_BUCKS) + return -EINVAL; + + buck = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_buck), GFP_KERNEL); if (!buck) return -ENOMEM; buck->lp = lp; - ret = lp8788_init_dvs(buck, id); + ret = lp8788_init_dvs(pdev, buck, id); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->buck_data[id] : NULL; cfg.driver_data = buck; cfg.regmap = lp->regmap; @@ -521,7 +516,7 @@ static int lp8788_buck_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_buck_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "BUCK%d regulator register err = %d\n", + dev_err(&pdev->dev, "BUCK%d regulator register err = %d\n", id + 1, ret); return ret; } diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 3792741..cd5a14a 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -88,11 +88,6 @@ #define ENABLE GPIOF_OUT_INIT_HIGH #define DISABLE GPIOF_OUT_INIT_LOW -enum lp8788_enable_mode { - REGISTER, - EXTPIN, -}; - enum lp8788_ldo_id { DLDO1, DLDO2, @@ -189,114 +184,38 @@ static enum lp8788_ldo_id lp8788_aldo_id[] = { ALDO10, }; -/* DLDO 7, 9 and 11, ALDO 1 ~ 5 and 7 - : can be enabled either by external pin or by i2c register */ -static enum lp8788_enable_mode -lp8788_get_ldo_enable_mode(struct lp8788_ldo *ldo, enum lp8788_ldo_id id) -{ - int ret; - u8 val, mask; - - ret = lp8788_read_byte(ldo->lp, LP8788_EN_SEL, &val); - if (ret) - return ret; - - switch (id) { - case DLDO7: - mask = LP8788_EN_SEL_DLDO7_M; - break; - case DLDO9: - case DLDO11: - mask = LP8788_EN_SEL_DLDO911_M; - break; - case ALDO1: - mask = LP8788_EN_SEL_ALDO1_M; - break; - case ALDO2 ... ALDO4: - mask = LP8788_EN_SEL_ALDO234_M; - break; - case ALDO5: - mask = LP8788_EN_SEL_ALDO5_M; - break; - case ALDO7: - mask = LP8788_EN_SEL_ALDO7_M; - break; - default: - return REGISTER; - } - - return val & mask ? EXTPIN : REGISTER; -} - -static int lp8788_ldo_ctrl_by_extern_pin(struct lp8788_ldo *ldo, int pinstate) -{ - struct lp8788_ldo_enable_pin *pin = ldo->en_pin; - - if (!pin) - return -EINVAL; - - if (gpio_is_valid(pin->gpio)) - gpio_set_value(pin->gpio, pinstate); - - return 0; -} - -static int lp8788_ldo_is_enabled_by_extern_pin(struct lp8788_ldo *ldo) -{ - struct lp8788_ldo_enable_pin *pin = ldo->en_pin; - - if (!pin) - return -EINVAL; - - return gpio_get_value(pin->gpio) ? 1 : 0; -} - static int lp8788_ldo_enable(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_ctrl_by_extern_pin(ldo, ENABLE); - case REGISTER: + if (ldo->en_pin) { + gpio_set_value(ldo->en_pin->gpio, ENABLE); + return 0; + } else { return regulator_enable_regmap(rdev); - default: - return -EINVAL; } } static int lp8788_ldo_disable(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_ctrl_by_extern_pin(ldo, DISABLE); - case REGISTER: + if (ldo->en_pin) { + gpio_set_value(ldo->en_pin->gpio, DISABLE); + return 0; + } else { return regulator_disable_regmap(rdev); - default: - return -EINVAL; } } static int lp8788_ldo_is_enabled(struct regulator_dev *rdev) { struct lp8788_ldo *ldo = rdev_get_drvdata(rdev); - enum lp8788_ldo_id id = rdev_get_id(rdev); - enum lp8788_enable_mode mode = lp8788_get_ldo_enable_mode(ldo, id); - switch (mode) { - case EXTPIN: - return lp8788_ldo_is_enabled_by_extern_pin(ldo); - case REGISTER: + if (ldo->en_pin) + return gpio_get_value(ldo->en_pin->gpio) ? 1 : 0; + else return regulator_is_enabled_regmap(rdev); - default: - return -EINVAL; - } } static int lp8788_ldo_enable_time(struct regulator_dev *rdev) @@ -616,10 +535,11 @@ static struct regulator_desc lp8788_aldo_desc[] = { }, }; -static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, +static int lp8788_gpio_request_ldo_en(struct platform_device *pdev, + struct lp8788_ldo *ldo, enum lp8788_ext_ldo_en_id id) { - struct device *dev = ldo->lp->dev; + struct device *dev = &pdev->dev; struct lp8788_ldo_enable_pin *pin = ldo->en_pin; int ret, gpio, pinstate; char *name[] = { @@ -647,7 +567,8 @@ static int lp8788_gpio_request_ldo_en(struct lp8788_ldo *ldo, return ret; } -static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, +static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, + struct lp8788_ldo *ldo, enum lp8788_ldo_id id) { int ret; @@ -693,9 +614,11 @@ static int lp8788_config_ldo_enable_mode(struct lp8788_ldo *ldo, ldo->en_pin = pdata->ldo_pin[enable_id]; - ret = lp8788_gpio_request_ldo_en(ldo, enable_id); - if (ret) + ret = lp8788_gpio_request_ldo_en(pdev, ldo, enable_id); + if (ret) { + ldo->en_pin = NULL; goto set_default_ldo_enable_mode; + } return ret; @@ -712,16 +635,16 @@ static int lp8788_dldo_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); if (!ldo) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(ldo, lp8788_dldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_dldo_id[id]); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->dldo_data[id] : NULL; cfg.driver_data = ldo; cfg.regmap = lp->regmap; @@ -729,7 +652,7 @@ static int lp8788_dldo_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_dldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "DLDO%d regulator register err = %d\n", + dev_err(&pdev->dev, "DLDO%d regulator register err = %d\n", id + 1, ret); return ret; } @@ -768,16 +691,16 @@ static int lp8788_aldo_probe(struct platform_device *pdev) struct regulator_dev *rdev; int ret; - ldo = devm_kzalloc(lp->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); + ldo = devm_kzalloc(&pdev->dev, sizeof(struct lp8788_ldo), GFP_KERNEL); if (!ldo) return -ENOMEM; ldo->lp = lp; - ret = lp8788_config_ldo_enable_mode(ldo, lp8788_aldo_id[id]); + ret = lp8788_config_ldo_enable_mode(pdev, ldo, lp8788_aldo_id[id]); if (ret) return ret; - cfg.dev = lp->dev; + cfg.dev = pdev->dev.parent; cfg.init_data = lp->pdata ? lp->pdata->aldo_data[id] : NULL; cfg.driver_data = ldo; cfg.regmap = lp->regmap; @@ -785,7 +708,7 @@ static int lp8788_aldo_probe(struct platform_device *pdev) rdev = regulator_register(&lp8788_aldo_desc[id], &cfg); if (IS_ERR(rdev)) { ret = PTR_ERR(rdev); - dev_err(lp->dev, "ALDO%d regulator register err = %d\n", + dev_err(&pdev->dev, "ALDO%d regulator register err = %d\n", id + 1, ret); return ret; } diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index f86da67..e68382d 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -61,10 +61,6 @@ struct tps6586x_regulator { int enable_bit[2]; int enable_reg[2]; - - /* for DVM regulators */ - int go_reg; - int go_bit; }; static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) @@ -72,37 +68,10 @@ static inline struct device *to_tps6586x_dev(struct regulator_dev *rdev) return rdev_get_dev(rdev)->parent; } -static int tps6586x_set_voltage_sel(struct regulator_dev *rdev, - unsigned selector) -{ - struct tps6586x_regulator *ri = rdev_get_drvdata(rdev); - struct device *parent = to_tps6586x_dev(rdev); - int ret, val, rid = rdev_get_id(rdev); - uint8_t mask; - - val = selector << (ffs(rdev->desc->vsel_mask) - 1); - mask = rdev->desc->vsel_mask; - - ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask); - if (ret) - return ret; - - /* Update go bit for DVM regulators */ - switch (rid) { - case TPS6586X_ID_LDO_2: - case TPS6586X_ID_LDO_4: - case TPS6586X_ID_SM_0: - case TPS6586X_ID_SM_1: - ret = tps6586x_set_bits(parent, ri->go_reg, 1 << ri->go_bit); - break; - } - return ret; -} - static struct regulator_ops tps6586x_regulator_ops = { .list_voltage = regulator_list_voltage_table, .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_sel = tps6586x_set_voltage_sel, + .set_voltage_sel = regulator_set_voltage_sel_regmap, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -142,7 +111,7 @@ static const unsigned int tps6586x_dvm_voltages[] = { }; #define TPS6586X_REGULATOR(_id, _pin_name, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ + ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ .desc = { \ .supply_name = _pin_name, \ .name = "REG-" #_id, \ @@ -156,29 +125,26 @@ static const unsigned int tps6586x_dvm_voltages[] = { .enable_mask = 1 << (ebit0), \ .vsel_reg = TPS6586X_##vreg, \ .vsel_mask = ((1 << (nbits)) - 1) << (shift), \ + .apply_reg = (goreg), \ + .apply_bit = (gobit), \ }, \ .enable_reg[0] = TPS6586X_SUPPLY##ereg0, \ .enable_bit[0] = (ebit0), \ .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ .enable_bit[1] = (ebit1), -#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ - .go_reg = TPS6586X_##goreg, \ - .go_bit = (gobit), - #define TPS6586X_LDO(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ { \ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ + ereg0, ebit0, ereg1, ebit1, 0, 0) \ } #define TPS6586X_DVM(_id, _pname, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ { \ TPS6586X_REGULATOR(_id, _pname, vdata, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1) \ - TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ + ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ } #define TPS6586X_SYS_REGULATOR() \ @@ -207,13 +173,13 @@ static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3, - ENB, 3, VCC2, 6), + ENB, 3, TPS6586X_VCC2, BIT(6)), TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3, - END, 3, VCC1, 6), + END, 3, TPS6586X_VCC1, BIT(6)), TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1, - ENB, 1, VCC1, 2), + ENB, 1, TPS6586X_VCC1, BIT(2)), TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0, - ENB, 0, VCC1, 0), + ENB, 0, TPS6586X_VCC1, BIT(0)), }; /* |