Grouping of BUCKs sharing ramp rate setting is as follow : BUCK[1, 6],
BUCK[3, 4], and BUCK[7, 8, 10]
+On S2MPS14 the LDO10, LDO11 and LDO12 can be configured to external control
+over GPIO. To turn this feature on this property must be added to the regulator
+sub-node:
+ - samsung,ext-control-gpios: GPIO specifier for one GPIO
+ controlling this regulator (enable/disable);
+Example:
+ LDO12 {
+ regulator-name = "V_EMMC_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+
The regulator constraints inside the regulator nodes use the standard regulator
bindings which are documented elsewhere.
int sleep_id;
};
+static const struct regulator_linear_range smps_low_ranges[] = {
+ REGULATOR_LINEAR_RANGE(500000, 0x1, 0x6, 0),
+ REGULATOR_LINEAR_RANGE(510000, 0x7, 0x79, 10000),
+ REGULATOR_LINEAR_RANGE(1650000, 0x7A, 0x7f, 0),
+};
+
+static const struct regulator_linear_range smps_high_ranges[] = {
+ REGULATOR_LINEAR_RANGE(1000000, 0x1, 0x6, 0),
+ REGULATOR_LINEAR_RANGE(1020000, 0x7, 0x79, 20000),
+ REGULATOR_LINEAR_RANGE(3300000, 0x7A, 0x7f, 0),
+};
+
static const struct regs_info palmas_regs_info[] = {
{
.name = "SMPS12",
return regmap_write(palmas->regmap[REGULATOR_SLAVE], addr, value);
}
-static int palmas_is_enabled_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®);
-
- reg &= PALMAS_SMPS12_CTRL_STATUS_MASK;
- reg >>= PALMAS_SMPS12_CTRL_STATUS_SHIFT;
-
- return !!(reg);
-}
-
-static int palmas_enable_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®);
-
- reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
- if (pmic->current_reg_mode[id])
- reg |= pmic->current_reg_mode[id];
- else
- reg |= SMPS_CTRL_MODE_ON;
-
- palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
-
- return 0;
-}
-
-static int palmas_disable_smps(struct regulator_dev *dev)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- unsigned int reg;
-
- palmas_smps_read(pmic->palmas, palmas_regs_info[id].ctrl_addr, ®);
-
- reg &= ~PALMAS_SMPS12_CTRL_MODE_ACTIVE_MASK;
-
- palmas_smps_write(pmic->palmas, palmas_regs_info[id].ctrl_addr, reg);
-
- return 0;
-}
-
static int palmas_set_mode_smps(struct regulator_dev *dev, unsigned int mode)
{
struct palmas_pmic *pmic = rdev_get_drvdata(dev);
return 0;
}
-static int palmas_list_voltage_smps(struct regulator_dev *dev,
- unsigned selector)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(dev);
- int id = rdev_get_id(dev);
- int mult = 1;
-
- /* Read the multiplier set in VSEL register to return
- * the correct voltage.
- */
- if (pmic->range[id])
- mult = 2;
-
- if (selector == 0)
- return 0;
- else if (selector < 6)
- return 500000 * mult;
- else
- /* Voltage is linear mapping starting from selector 6,
- * volt = (0.49V + ((selector - 5) * 0.01V)) * RANGE
- * RANGE is either x1 or x2
- */
- return (490000 + ((selector - 5) * 10000)) * mult;
-}
-
-static int palmas_map_voltage_smps(struct regulator_dev *rdev,
- int min_uV, int max_uV)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int ret, voltage;
-
- if (min_uV == 0)
- return 0;
-
- if (pmic->range[id]) { /* RANGE is x2 */
- if (min_uV < 1000000)
- min_uV = 1000000;
- ret = DIV_ROUND_UP(min_uV - 1000000, 20000) + 6;
- } else { /* RANGE is x1 */
- if (min_uV < 500000)
- min_uV = 500000;
- ret = DIV_ROUND_UP(min_uV - 500000, 10000) + 6;
- }
-
- /* Map back into a voltage to verify we're still in bounds */
- voltage = palmas_list_voltage_smps(rdev, ret);
- if (voltage < min_uV || voltage > max_uV)
- return -EINVAL;
-
- return ret;
-}
-
-static int palma_smps_set_voltage_smps_time_sel(struct regulator_dev *rdev,
- unsigned int old_selector, unsigned int new_selector)
-{
- struct palmas_pmic *pmic = rdev_get_drvdata(rdev);
- int id = rdev_get_id(rdev);
- int old_uv, new_uv;
- unsigned int ramp_delay = pmic->ramp_delay[id];
-
- if (!ramp_delay)
- return 0;
-
- old_uv = palmas_list_voltage_smps(rdev, old_selector);
- if (old_uv < 0)
- return old_uv;
-
- new_uv = palmas_list_voltage_smps(rdev, new_selector);
- if (new_uv < 0)
- return new_uv;
-
- return DIV_ROUND_UP(abs(old_uv - new_uv), ramp_delay);
-}
-
static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev,
int ramp_delay)
{
}
static struct regulator_ops palmas_ops_smps = {
- .is_enabled = palmas_is_enabled_smps,
- .enable = palmas_enable_smps,
- .disable = palmas_disable_smps,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.set_mode = palmas_set_mode_smps,
.get_mode = palmas_get_mode_smps,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = palmas_list_voltage_smps,
- .map_voltage = palmas_map_voltage_smps,
- .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = palmas_smps_set_ramp_delay,
};
.get_mode = palmas_get_mode_smps,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .list_voltage = palmas_list_voltage_smps,
- .map_voltage = palmas_map_voltage_smps,
- .set_voltage_time_sel = palma_smps_set_voltage_smps_time_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = palmas_smps_set_ramp_delay,
};
* ranges. Read the current smps mode for later use.
*/
addr = palmas_regs_info[id].vsel_addr;
+ pmic->desc[id].n_linear_ranges = 3;
ret = palmas_smps_read(pmic->palmas, addr, ®);
if (ret)
return ret;
if (reg & PALMAS_SMPS12_VOLTAGE_RANGE)
pmic->range[id] = 1;
+ if (pmic->range[id])
+ pmic->desc[id].linear_ranges = smps_high_ranges;
+ else
+ pmic->desc[id].linear_ranges = smps_low_ranges;
if (reg_init && reg_init->roof_floor)
pmic->desc[id].ops =
3000000
};
-static int pbias_regulator_enable(struct regulator_dev *rdev)
-{
- struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
- const struct pbias_reg_info *info = data->info;
-
- return regmap_update_bits(data->syscon, rdev->desc->enable_reg,
- info->enable_mask, info->enable);
-}
-
-static int pbias_regulator_is_enable(struct regulator_dev *rdev)
-{
- struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
- const struct pbias_reg_info *info = data->info;
- int value;
-
- regmap_read(data->syscon, rdev->desc->enable_reg, &value);
-
- return (value & info->enable_mask) == info->enable;
-}
-
static struct regulator_ops pbias_regulator_voltage_ops = {
.list_voltage = regulator_list_voltage_table,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
- .enable = pbias_regulator_enable,
+ .enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
- .is_enabled = pbias_regulator_is_enable,
+ .is_enabled = regulator_is_enabled_regmap,
};
static const struct pbias_reg_info pbias_mmc_omap2430 = {
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
* count, GFP_KERNEL);
- if (drvdata == NULL) {
- dev_err(&pdev->dev, "Failed to allocate device data\n");
+ if (!drvdata)
return -ENOMEM;
- }
syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(syscon))
drvdata[data_idx].desc.vsel_mask = info->vmode;
drvdata[data_idx].desc.enable_reg = res->start;
drvdata[data_idx].desc.enable_mask = info->enable_mask;
+ drvdata[data_idx].desc.enable_val = info->enable;
cfg.init_data = pbias_matches[idx].init_data;
cfg.driver_data = &drvdata[data_idx];
};
static struct regulator_ops pfuze100_fixed_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
.list_voltage = regulator_list_voltage_linear,
};
};
static struct regulator_ops pfuze100_swb_regulator_ops = {
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
.list_voltage = regulator_list_voltage_table,
.map_voltage = regulator_map_voltage_ascend,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.volt_table = voltages, \
.vsel_reg = (base), \
.vsel_mask = (mask), \
+ .enable_reg = (base), \
+ .enable_mask = 0x48, \
}, \
}
config.init_data = init_data;
config.driver_data = pfuze_chip;
config.of_node = match_of_node(i);
+ config.ena_gpio = -EINVAL;
pfuze_chip->regulators[i] =
devm_regulator_register(&client->dev, desc, &config);
unsigned int ramp_delay = 0;
int old_volt, new_volt;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPA01_BUCK2:
case S2MPA01_BUCK4:
ramp_delay = s2mpa01->ramp_delay24;
unsigned int ramp_enable = 1, enable_shift = 0;
int ret;
- switch (rdev->desc->id) {
+ switch (rdev_get_id(rdev)) {
case S2MPA01_BUCK1:
enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;
if (!ramp_delay) {
if (!ramp_enable)
goto ramp_disable;
- ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
- 1 << enable_shift, 1 << enable_shift);
- if (ret) {
- dev_err(&rdev->dev, "failed to enable ramp rate\n");
- return ret;
+ /* Ramp delay can be enabled/disabled only for buck[1234] */
+ if (rdev_get_id(rdev) >= S2MPA01_BUCK1 &&
+ rdev_get_id(rdev) <= S2MPA01_BUCK4) {
+ ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
}
ramp_val = get_ramp_delay(ramp_delay);
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/of_gpio.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/s2mps14.h>
* was enabled.
*/
unsigned int s2mps14_suspend_state:30;
+ /* Array of size rdev_num with GPIO-s for external sleep control */
+ int *ext_control_gpio;
};
static int get_ramp_delay(int ramp_delay)
if (!ramp_enable)
goto ramp_disable;
- ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
- 1 << enable_shift, 1 << enable_shift);
- if (ret) {
- dev_err(&rdev->dev, "failed to enable ramp rate\n");
- return ret;
+ /* Ramp delay can be enabled/disabled only for buck[2346] */
+ if ((rdev_get_id(rdev) >= S2MPS11_BUCK2 &&
+ rdev_get_id(rdev) <= S2MPS11_BUCK4) ||
+ rdev_get_id(rdev) == S2MPS11_BUCK6) {
+ ret = regmap_update_bits(rdev->regmap, S2MPS11_REG_RAMP,
+ 1 << enable_shift, 1 << enable_shift);
+ if (ret) {
+ dev_err(&rdev->dev, "failed to enable ramp rate\n");
+ return ret;
+ }
}
ramp_val = get_ramp_delay(ramp_delay);
if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
val = S2MPS14_ENABLE_SUSPEND;
+ else if (gpio_is_valid(s2mps11->ext_control_gpio[rdev_get_id(rdev)]))
+ val = S2MPS14_ENABLE_EXT_CONTROL;
else
val = rdev->desc->enable_mask;
regulator_desc_s2mps14_buck1235(5),
};
+static int s2mps14_pmic_enable_ext_control(struct s2mps11_info *s2mps11,
+ struct regulator_dev *rdev)
+{
+ return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
+ rdev->desc->enable_mask, S2MPS14_ENABLE_EXT_CONTROL);
+}
+
+static void s2mps14_pmic_dt_parse_ext_control_gpio(struct platform_device *pdev,
+ struct of_regulator_match *rdata, struct s2mps11_info *s2mps11)
+{
+ int *gpio = s2mps11->ext_control_gpio;
+ unsigned int i;
+ unsigned int valid_regulators[3] = { S2MPS14_LDO10, S2MPS14_LDO11,
+ S2MPS14_LDO12 };
+
+ for (i = 0; i < ARRAY_SIZE(valid_regulators); i++) {
+ unsigned int reg = valid_regulators[i];
+
+ if (!rdata[reg].init_data || !rdata[reg].of_node)
+ continue;
+
+ gpio[reg] = of_get_named_gpio(rdata[reg].of_node,
+ "samsung,ext-control-gpios", 0);
+ if (gpio_is_valid(gpio[reg]))
+ dev_dbg(&pdev->dev, "Using GPIO %d for ext-control over %d/%s\n",
+ gpio[reg], reg, rdata[reg].name);
+ }
+}
+
+static int s2mps11_pmic_dt_parse(struct platform_device *pdev,
+ struct of_regulator_match *rdata, struct s2mps11_info *s2mps11,
+ enum sec_device_type dev_type)
+{
+ struct device_node *reg_np;
+
+ reg_np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
+ if (!reg_np) {
+ dev_err(&pdev->dev, "could not find regulators sub-node\n");
+ return -EINVAL;
+ }
+
+ of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
+ if (dev_type == S2MPS14X)
+ s2mps14_pmic_dt_parse_ext_control_gpio(pdev, rdata, s2mps11);
+
+ of_node_put(reg_np);
+
+ return 0;
+}
+
static int s2mps11_pmic_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct sec_platform_data *pdata = iodev->pdata;
+ struct sec_platform_data *pdata = NULL;
struct of_regulator_match *rdata = NULL;
- struct device_node *reg_np = NULL;
struct regulator_config config = { };
struct s2mps11_info *s2mps11;
int i, ret = 0;
return -EINVAL;
};
+ s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev,
+ sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
+ GFP_KERNEL);
+ if (!s2mps11->ext_control_gpio)
+ return -ENOMEM;
+ /*
+ * 0 is a valid GPIO so initialize all GPIO-s to negative value
+ * to indicate that external control won't be used for this regulator.
+ */
+ for (i = 0; i < s2mps11->rdev_num; i++)
+ s2mps11->ext_control_gpio[i] = -EINVAL;
+
if (!iodev->dev->of_node) {
- if (pdata) {
+ if (iodev->pdata) {
+ pdata = iodev->pdata;
goto common_reg;
} else {
dev_err(pdev->dev.parent,
for (i = 0; i < s2mps11->rdev_num; i++)
rdata[i].name = regulators[i].name;
- reg_np = of_get_child_by_name(iodev->dev->of_node, "regulators");
- if (!reg_np) {
- dev_err(&pdev->dev, "could not find regulators sub-node\n");
- ret = -EINVAL;
+ ret = s2mps11_pmic_dt_parse(pdev, rdata, s2mps11, dev_type);
+ if (ret)
goto out;
- }
-
- of_regulator_match(&pdev->dev, reg_np, rdata, s2mps11->rdev_num);
- of_node_put(reg_np);
common_reg:
platform_set_drvdata(pdev, s2mps11);
config.dev = &pdev->dev;
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
+ config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
for (i = 0; i < s2mps11->rdev_num; i++) {
struct regulator_dev *regulator;
- if (!reg_np) {
+ if (pdata) {
config.init_data = pdata->regulators[i].initdata;
config.of_node = pdata->regulators[i].reg_node;
} else {
config.init_data = rdata[i].init_data;
config.of_node = rdata[i].of_node;
}
+ config.ena_gpio = s2mps11->ext_control_gpio[i];
regulator = devm_regulator_register(&pdev->dev,
®ulators[i], &config);
i);
goto out;
}
+
+ if (gpio_is_valid(s2mps11->ext_control_gpio[i])) {
+ ret = s2mps14_pmic_enable_ext_control(s2mps11,
+ regulator);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to enable GPIO control over %s: %d\n",
+ regulator->desc->name, ret);
+ goto out;
+ }
+ }
}
out:
#define S2MPS14_ENABLE_SHIFT 6
/* On/Off controlled by PWREN */
#define S2MPS14_ENABLE_SUSPEND (0x01 << S2MPS14_ENABLE_SHIFT)
+/* On/Off controlled by LDO10EN or EMMCEN */
+#define S2MPS14_ENABLE_EXT_CONTROL (0x00 << S2MPS14_ENABLE_SHIFT)
#define S2MPS14_LDO_N_VOLTAGES (S2MPS14_LDO_VSEL_MASK + 1)
#define S2MPS14_BUCK_N_VOLTAGES (S2MPS14_BUCK_VSEL_MASK + 1)