lkml.org 
[lkml]   [2020]   [Nov]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Date
    Subject[PATCH 5/9] regulator: da9121: Add support for device variants via devicetree
    Add devicetree configuration and device variant parameters. Use the latter to
    enable the check and use of parameters specific to dual buck variants.

    Signed-off-by: Adam Ward <Adam.Ward.opensource@diasemi.com>
    ---
    drivers/regulator/da9121-regulator.c | 157 ++++++++++++++++++++++++++++++++++-
    include/linux/regulator/da9121.h | 11 +++
    2 files changed, 167 insertions(+), 1 deletion(-)

    diff --git a/drivers/regulator/da9121-regulator.c b/drivers/regulator/da9121-regulator.c
    index 76932ba..5020774 100644
    --- a/drivers/regulator/da9121-regulator.c
    +++ b/drivers/regulator/da9121-regulator.c
    @@ -1,7 +1,21 @@
    // SPDX-License-Identifier: GPL-2.0-only
    -/* Copyright (C) 2020 Axis Communications AB */
    +/* Copyright (C) 2020 Axis Communications AB
    + *
    + * DA9121 Single-channel dual-phase 10A buck converter
    + *
    + * Copyright (C) 2020 Dialog Semiconductor
    + *
    + * DA9130 Single-channel dual-phase 10A buck converter (Automotive)
    + * DA9217 Single-channel dual-phase 6A buck converter
    + * DA9122 Dual-channel single-phase 5A buck converter
    + * DA9131 Dual-channel single-phase 5A buck converter (Automotive)
    + * DA9220 Dual-channel single-phase 3A buck converter
    + * DA9132 Dual-channel single-phase 3A buck converter (Automotive)
    + *
    + */

    #include <linux/of_device.h>
    +#include <linux/of_gpio.h>
    #include <linux/regulator/of_regulator.h>
    #include <linux/regulator/machine.h>
    #include <linux/regulator/driver.h>
    @@ -16,11 +30,68 @@
    /* Chip data */
    struct da9121 {
    struct device *dev;
    + struct da9121_pdata *pdata;
    struct regmap *regmap;
    struct regulator_dev *rdev[DA9121_IDX_MAX];
    int variant_id;
    };

    +/* Define ranges for different variants, enabling translation to/from
    + * registers. Maximums give scope to allow for transients.
    + */
    +struct da9121_range {
    + int val_min;
    + int val_max;
    + int val_stp;
    + int reg_min;
    + int reg_max;
    +};
    +
    +struct da9121_range da9121_10A_2phase_current = {
    + .val_min = 7000000,
    + .val_max = 20000000,
    + .val_stp = 1000000,
    + .reg_min = 1,
    + .reg_max = 14,
    +};
    +
    +struct da9121_range da9121_6A_2phase_current = {
    + .val_min = 7000000,
    + .val_max = 12000000,
    + .val_stp = 1000000,
    + .reg_min = 1,
    + .reg_max = 6,
    +};
    +
    +struct da9121_range da9121_5A_1phase_current = {
    + .val_min = 3500000,
    + .val_max = 10000000,
    + .val_stp = 500000,
    + .reg_min = 1,
    + .reg_max = 14,
    +};
    +
    +struct da9121_range da9121_3A_1phase_current = {
    + .val_min = 3500000,
    + .val_max = 6000000,
    + .val_stp = 500000,
    + .reg_min = 1,
    + .reg_max = 6,
    +};
    +
    +struct da9121_variant_info {
    + int num_bucks;
    + int num_phases;
    + struct da9121_range *current_range;
    +};
    +
    +static const struct da9121_variant_info variant_parameters[] = {
    + { 1, 2, &da9121_10A_2phase_current }, //DA9121_TYPE_DA9121_DA9130
    + { 2, 1, &da9121_3A_1phase_current }, //DA9121_TYPE_DA9220_DA9132
    + { 2, 1, &da9121_5A_1phase_current }, //DA9121_TYPE_DA9122_DA9131
    + { 1, 2, &da9121_6A_2phase_current }, //DA9121_TYPE_DA9217
    +};
    +
    static const struct regulator_ops da9121_buck_ops = {
    .enable = regulator_enable_regmap,
    .disable = regulator_disable_regmap,
    @@ -163,6 +234,86 @@ struct da9121 {
    [DA9121_TYPE_DA9217] = { &da9217_reg, NULL },
    };

    +#ifdef CONFIG_OF
    +static struct da9121_pdata *da9121_parse_regulators_dt(struct da9121 *chip)
    +{
    + struct da9121_pdata *pdata;
    + struct device_node *node;
    + int num = 0;
    + int ret = 0;
    + int i, n;
    + enum gpiod_flags flags = GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE;
    +
    + node = of_get_child_by_name(chip->dev->of_node, "regulators");
    + if (!node) {
    + dev_err(chip->dev, "Regulators node not found\n");
    + return ERR_PTR(-ENODEV);
    + }
    +
    + num = of_regulator_match(chip->dev, node, da9121_matches,
    + ARRAY_SIZE(da9121_matches));
    + of_node_put(node);
    + if (num < 0) {
    + dev_err(chip->dev, "Failed to match regulators\n");
    + return ERR_PTR(-EINVAL);
    + }
    +
    + /* interrupt assumptions require at least one buck to be configured */
    + if (num == 0) {
    + dev_err(chip->dev, "Did not match any regulators in the DT\n");
    + return ERR_PTR(-EINVAL);
    + }
    +
    + pdata = devm_kzalloc(chip->dev, sizeof(*pdata), GFP_KERNEL);
    + if (!pdata)
    + return ERR_PTR(-ENOMEM);
    +
    + pdata->num_buck = num;
    +
    + n = 0;
    + for (i = 0; i < ARRAY_SIZE(da9121_matches); i++) {
    + if (!da9121_matches[i].init_data)
    + continue;
    +
    + pdata->init_data[n] = da9121_matches[i].init_data;
    + pdata->reg_node[n] = da9121_matches[i].of_node;
    + pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(chip->dev,
    + da9121_matches[i].of_node,
    + "enable-gpios",
    + 0,
    + flags,
    + "da9121-enable");
    +
    + if (IS_ERR(pdata->gpiod_ren[n]))
    + pdata->gpiod_ren[n] = NULL;
    +
    + if (variant_parameters[chip->variant_id].num_bucks == 2) {
    + uint32_t ripple_cancel;
    + uint32_t reg = (i ? DA9xxx_REG_BUCK_BUCK2_7
    + : DA9121_REG_BUCK_BUCK1_7);
    + if (!of_property_read_u32(da9121_matches[i].of_node,
    + "dlg,ripple-cancel",
    + &ripple_cancel)) {
    + //write to BUCK_BUCKx_7 : CHx_RIPPLE_CANCEL
    + ret = regmap_update_bits(chip->regmap, reg,
    + DA9xxx_MASK_BUCK_BUCKx_7_CHx_RIPPLE_CANCEL,
    + ripple_cancel);
    + if (ret < 0)
    + dev_err(chip->dev, "Cannot update BUCK register %02x, err: %d\n", reg, ret);
    + }
    + }
    + n++;
    + }
    +
    + return pdata;
    +}
    +#else
    +static struct da9121_pdata *da9121_parse_regulators_dt(struct da9121 *chip)
    +{
    + return ERR_PTR(-ENODEV);
    +}
    +#endif
    +
    /* DA9121 chip register model */
    static const struct regmap_range da9121_1ch_readable_ranges[] = {
    regmap_reg_range(DA9121_REG_SYS_STATUS_0, DA9121_REG_SYS_MASK_3),
    @@ -445,12 +596,16 @@ static int da9121_i2c_probe(struct i2c_client *i2c,
    goto error;
    }

    + chip->pdata = i2c->dev.platform_data;
    chip->variant_id = da9121_of_get_id(&i2c->dev);

    ret = da9121_assign_chip_model(i2c, chip);
    if (ret < 0)
    goto error;

    + if (!chip->pdata)
    + chip->pdata = da9121_parse_regulators_dt(chip);
    +
    config.dev = &i2c->dev;
    config.of_node = dev->of_node;
    config.regmap = chip->regmap;
    diff --git a/include/linux/regulator/da9121.h b/include/linux/regulator/da9121.h
    index c31180d..62d9d257 100644
    --- a/include/linux/regulator/da9121.h
    +++ b/include/linux/regulator/da9121.h
    @@ -16,10 +16,21 @@
    #ifndef __LINUX_REGULATOR_DA9121_H
    #define __LINUX_REGULATOR_DA9121_H

    +#include <linux/regulator/machine.h>
    +
    +struct gpio_desc;
    +
    enum {
    DA9121_IDX_BUCK1,
    DA9121_IDX_BUCK2,
    DA9121_IDX_MAX
    };

    +struct da9121_pdata {
    + int num_buck;
    + struct gpio_desc *gpiod_ren[DA9121_IDX_MAX];
    + struct device_node *reg_node[DA9121_IDX_MAX];
    + struct regulator_init_data *init_data[DA9121_IDX_MAX];
    +};
    +
    #endif
    --
    1.9.1
    \
     
     \ /
      Last update: 2020-11-20 13:16    [W:2.043 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site