--- zzzz-none-000/linux-3.10.107/drivers/regulator/tps65090-regulator.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/regulator/tps65090-regulator.c 2021-02-04 17:41:59.000000000 +0000 @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -28,49 +29,224 @@ #include #include +#define MAX_CTRL_READ_TRIES 5 +#define MAX_FET_ENABLE_TRIES 1000 + +#define CTRL_EN_BIT 0 /* Regulator enable bit, active high */ +#define CTRL_WT_BIT 2 /* Regulator wait time 0 bit */ +#define CTRL_PG_BIT 4 /* Regulator power good bit, 1=good */ +#define CTRL_TO_BIT 7 /* Regulator timeout bit, 1=wait */ + +#define MAX_OVERCURRENT_WAIT 3 /* Overcurrent wait must be <= this */ + +/** + * struct tps65090_regulator - Per-regulator data for a tps65090 regulator + * + * @dev: Pointer to our device. + * @desc: The struct regulator_desc for the regulator. + * @rdev: The struct regulator_dev for the regulator. + * @overcurrent_wait_valid: True if overcurrent_wait is valid. + * @overcurrent_wait: For FETs, the value to put in the WTFET bitfield. + */ + struct tps65090_regulator { struct device *dev; struct regulator_desc *desc; struct regulator_dev *rdev; + bool overcurrent_wait_valid; + int overcurrent_wait; }; static struct regulator_ops tps65090_ext_control_ops = { }; -static struct regulator_ops tps65090_reg_contol_ops = { +/** + * tps65090_reg_set_overcurrent_wait - Setup overcurrent wait + * + * This will set the overcurrent wait time based on what's in the regulator + * info. + * + * @ri: Overall regulator data + * @rdev: Regulator device + * + * Return: 0 if no error, non-zero if there was an error writing the register. + */ +static int tps65090_reg_set_overcurrent_wait(struct tps65090_regulator *ri, + struct regulator_dev *rdev) +{ + int ret; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + MAX_OVERCURRENT_WAIT << CTRL_WT_BIT, + ri->overcurrent_wait << CTRL_WT_BIT); + if (ret) { + dev_err(&rdev->dev, "Error updating overcurrent wait %#x\n", + rdev->desc->enable_reg); + } + + return ret; +} + +/** + * tps65090_try_enable_fet - Try to enable a FET + * + * @rdev: Regulator device + * + * Return: 0 if ok, -ENOTRECOVERABLE if the FET power good bit did not get + * set, or some other -ve value if another error occurred (e.g. i2c error) + */ +static int tps65090_try_enable_fet(struct regulator_dev *rdev) +{ + unsigned int control; + int ret, i; + + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); + if (ret < 0) { + dev_err(&rdev->dev, "Error in updating reg %#x\n", + rdev->desc->enable_reg); + return ret; + } + + for (i = 0; i < MAX_CTRL_READ_TRIES; i++) { + ret = regmap_read(rdev->regmap, rdev->desc->enable_reg, + &control); + if (ret < 0) + return ret; + + if (!(control & BIT(CTRL_TO_BIT))) + break; + + usleep_range(1000, 1500); + } + if (!(control & BIT(CTRL_PG_BIT))) + return -ENOTRECOVERABLE; + + return 0; +} + +/** + * tps65090_fet_enable - Enable a FET, trying a few times if it fails + * + * Some versions of the tps65090 have issues when turning on the FETs. + * This function goes through several steps to ensure the best chance of the + * FET going on. Specifically: + * - We'll make sure that we bump the "overcurrent wait" to the maximum, which + * increases the chances that we'll turn on properly. + * - We'll retry turning the FET on multiple times (turning off in between). + * + * @rdev: Regulator device + * + * Return: 0 if ok, non-zero if it fails. + */ +static int tps65090_fet_enable(struct regulator_dev *rdev) +{ + int ret, tries; + + /* + * Try enabling multiple times until we succeed since sometimes the + * first try times out. + */ + tries = 0; + while (true) { + ret = tps65090_try_enable_fet(rdev); + if (!ret) + break; + if (ret != -ENOTRECOVERABLE || tries == MAX_FET_ENABLE_TRIES) + goto err; + + /* Try turning the FET off (and then on again) */ + ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); + if (ret) + goto err; + + tries++; + } + + if (tries) + dev_warn(&rdev->dev, "reg %#x enable ok after %d tries\n", + rdev->desc->enable_reg, tries); + + return 0; +err: + dev_warn(&rdev->dev, "reg %#x enable failed\n", rdev->desc->enable_reg); + WARN_ON(1); + + return ret; +} + +static struct regulator_ops tps65090_reg_control_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, }; +static struct regulator_ops tps65090_fet_control_ops = { + .enable = tps65090_fet_enable, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + static struct regulator_ops tps65090_ldo_ops = { }; -#define tps65090_REG_DESC(_id, _sname, _en_reg, _ops) \ +#define tps65090_REG_DESC(_id, _sname, _en_reg, _en_bits, _nvolt, _volt, _ops) \ { \ .name = "TPS65090_RAILS"#_id, \ .supply_name = _sname, \ .id = TPS65090_REGULATOR_##_id, \ + .n_voltages = _nvolt, \ .ops = &_ops, \ + .fixed_uV = _volt, \ .enable_reg = _en_reg, \ - .enable_mask = BIT(0), \ + .enable_val = _en_bits, \ + .enable_mask = _en_bits, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } +#define tps65090_REG_FIXEDV(_id, _sname, en_reg, _en_bits, _volt, _ops) \ + tps65090_REG_DESC(_id, _sname, en_reg, _en_bits, 1, _volt, _ops) + +#define tps65090_REG_SWITCH(_id, _sname, en_reg, _en_bits, _ops) \ + tps65090_REG_DESC(_id, _sname, en_reg, _en_bits, 0, 0, _ops) + static struct regulator_desc tps65090_regulator_desc[] = { - tps65090_REG_DESC(DCDC1, "vsys1", 0x0C, tps65090_reg_contol_ops), - tps65090_REG_DESC(DCDC2, "vsys2", 0x0D, tps65090_reg_contol_ops), - tps65090_REG_DESC(DCDC3, "vsys3", 0x0E, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET1, "infet1", 0x0F, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET2, "infet2", 0x10, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET3, "infet3", 0x11, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET4, "infet4", 0x12, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET5, "infet5", 0x13, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET6, "infet6", 0x14, tps65090_reg_contol_ops), - tps65090_REG_DESC(FET7, "infet7", 0x15, tps65090_reg_contol_ops), - tps65090_REG_DESC(LDO1, "vsys-l1", 0, tps65090_ldo_ops), - tps65090_REG_DESC(LDO2, "vsys-l2", 0, tps65090_ldo_ops), + tps65090_REG_FIXEDV(DCDC1, "vsys1", 0x0C, BIT(CTRL_EN_BIT), 5000000, + tps65090_reg_control_ops), + tps65090_REG_FIXEDV(DCDC2, "vsys2", 0x0D, BIT(CTRL_EN_BIT), 3300000, + tps65090_reg_control_ops), + tps65090_REG_SWITCH(DCDC3, "vsys3", 0x0E, BIT(CTRL_EN_BIT), + tps65090_reg_control_ops), + + tps65090_REG_SWITCH(FET1, "infet1", 0x0F, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET2, "infet2", 0x10, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET3, "infet3", 0x11, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET4, "infet4", 0x12, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET5, "infet5", 0x13, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET6, "infet6", 0x14, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + tps65090_REG_SWITCH(FET7, "infet7", 0x15, + BIT(CTRL_EN_BIT) | BIT(CTRL_PG_BIT), + tps65090_fet_control_ops), + + tps65090_REG_FIXEDV(LDO1, "vsys-l1", 0, 0, 5000000, + tps65090_ldo_ops), + tps65090_REG_FIXEDV(LDO2, "vsys-l2", 0, 0, 3300000, + tps65090_ldo_ops), }; static inline bool is_dcdc(int id) @@ -136,7 +312,11 @@ gpio_flag = GPIOF_OUT_INIT_HIGH; config->ena_gpio = tps_pdata->gpio; + config->ena_gpio_initialized = true; config->ena_gpio_flags = gpio_flag; + } else { + config->ena_gpio = -EINVAL; + config->ena_gpio_initialized = false; } } @@ -168,19 +348,15 @@ tps65090_pdata = devm_kzalloc(&pdev->dev, sizeof(*tps65090_pdata), GFP_KERNEL); - if (!tps65090_pdata) { - dev_err(&pdev->dev, "Memory alloc for tps65090_pdata failed\n"); + if (!tps65090_pdata) return ERR_PTR(-ENOMEM); - } reg_pdata = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*reg_pdata), GFP_KERNEL); - if (!reg_pdata) { - dev_err(&pdev->dev, "Memory alloc for reg_pdata failed\n"); + if (!reg_pdata) return ERR_PTR(-ENOMEM); - } - regulators = of_find_node_by_name(np, "regulators"); + regulators = of_get_child_by_name(np, "regulators"); if (!regulators) { dev_err(&pdev->dev, "regulator node not found\n"); return ERR_PTR(-ENODEV); @@ -188,6 +364,7 @@ ret = of_regulator_match(&pdev->dev, regulators, tps65090_matches, ARRAY_SIZE(tps65090_matches)); + of_node_put(regulators); if (ret < 0) { dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); @@ -212,6 +389,11 @@ rpdata->gpio = of_get_named_gpio(np, "dcdc-ext-control-gpios", 0); + if (of_property_read_u32(tps65090_matches[idx].of_node, + "ti,overcurrent-wait", + &rpdata->overcurrent_wait) == 0) + rpdata->overcurrent_wait_valid = true; + tps65090_pdata->reg_pdata[idx] = rpdata; } return tps65090_pdata; @@ -252,10 +434,8 @@ pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic), GFP_KERNEL); - if (!pmic) { - dev_err(&pdev->dev, "mem alloc for pmic failed\n"); + if (!pmic) return -ENOMEM; - } for (num = 0; num < TPS65090_REGULATOR_MAX; num++) { tps_pdata = tps65090_pdata->reg_pdata[num]; @@ -263,6 +443,11 @@ ri = &pmic[num]; ri->dev = &pdev->dev; ri->desc = &tps65090_regulator_desc[num]; + if (tps_pdata) { + ri->overcurrent_wait_valid = + tps_pdata->overcurrent_wait_valid; + ri->overcurrent_wait = tps_pdata->overcurrent_wait; + } /* * TPS5090 DCDC support the control from external digital input. @@ -279,7 +464,7 @@ if (ret < 0) { dev_err(&pdev->dev, "failed disable ext control\n"); - goto scrub; + return ret; } } } @@ -296,58 +481,38 @@ else config.of_node = NULL; - rdev = regulator_register(ri->desc, &config); + rdev = devm_regulator_register(&pdev->dev, ri->desc, &config); if (IS_ERR(rdev)) { dev_err(&pdev->dev, "failed to register regulator %s\n", ri->desc->name); - ret = PTR_ERR(rdev); - goto scrub; + return PTR_ERR(rdev); } ri->rdev = rdev; + if (ri->overcurrent_wait_valid) { + ret = tps65090_reg_set_overcurrent_wait(ri, rdev); + if (ret < 0) + return ret; + } + /* Enable external control if it is require */ if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data && tps_pdata->enable_ext_control) { ret = tps65090_config_ext_control(ri, true); - if (ret < 0) { - /* Increment num to get unregister rdev */ - num++; - goto scrub; - } + if (ret < 0) + return ret; } } platform_set_drvdata(pdev, pmic); return 0; - -scrub: - while (--num >= 0) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return ret; -} - -static int tps65090_regulator_remove(struct platform_device *pdev) -{ - struct tps65090_regulator *pmic = platform_get_drvdata(pdev); - struct tps65090_regulator *ri; - int num; - - for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) { - ri = &pmic[num]; - regulator_unregister(ri->rdev); - } - return 0; } static struct platform_driver tps65090_regulator_driver = { .driver = { .name = "tps65090-pmic", - .owner = THIS_MODULE, }, .probe = tps65090_regulator_probe, - .remove = tps65090_regulator_remove, }; static int __init tps65090_regulator_init(void)