Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: bq257xx: Add bq257xx boost regulator driver

Add support for the boost regulator found in the Texas Instruments
BQ25703. The boost regulator is capable of outputting between 4.48
and 20.8 volts and between 0 and 6.35 amps.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Reviewed-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20250904160530.66178-5-macroalpha82@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>

authored by

Chris Morgan and committed by
Lee Jones
981dd162 1cc017b7

+195
+8
drivers/regulator/Kconfig
··· 297 297 This driver can also be built as a module. If so, the module 298 298 will be called bd96801-regulator. 299 299 300 + config REGULATOR_BQ257XX 301 + tristate "TI BQ257XX regulator family" 302 + depends on MFD_BQ257XX 303 + depends on GPIOLIB || COMPILE_TEST 304 + help 305 + Say Y to enable support for the boost regulator function of 306 + the BQ257XX family of charger circuits. 307 + 300 308 config REGULATOR_CPCAP 301 309 tristate "Motorola CPCAP regulator" 302 310 depends on MFD_CPCAP
+1
drivers/regulator/Makefile
··· 38 38 obj-$(CONFIG_REGULATOR_BD718XX) += bd718x7-regulator.o 39 39 obj-$(CONFIG_REGULATOR_BD9571MWV) += bd9571mwv-regulator.o 40 40 obj-$(CONFIG_REGULATOR_BD957XMUF) += bd9576-regulator.o 41 + obj-$(CONFIG_REGULATOR_BQ257XX) += bq257xx-regulator.o 41 42 obj-$(CONFIG_REGULATOR_DA903X) += da903x-regulator.o 42 43 obj-$(CONFIG_REGULATOR_BD96801) += bd96801-regulator.o 43 44 obj-$(CONFIG_REGULATOR_DA9052) += da9052-regulator.o
+186
drivers/regulator/bq257xx-regulator.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * BQ257XX Battery Charger Driver 4 + * Copyright (C) 2025 Chris Morgan <macromorgan@hotmail.com> 5 + */ 6 + 7 + #include <linux/bitfield.h> 8 + #include <linux/err.h> 9 + #include <linux/gpio/consumer.h> 10 + #include <linux/mfd/bq257xx.h> 11 + #include <linux/of.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/regmap.h> 14 + #include <linux/regulator/driver.h> 15 + #include <linux/regulator/of_regulator.h> 16 + 17 + struct bq257xx_reg_data { 18 + struct bq257xx_device *bq; 19 + struct regulator_dev *bq257xx_reg; 20 + struct gpio_desc *otg_en_gpio; 21 + struct regulator_desc desc; 22 + }; 23 + 24 + static int bq25703_vbus_get_cur_limit(struct regulator_dev *rdev) 25 + { 26 + struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev); 27 + int ret; 28 + unsigned int reg; 29 + 30 + ret = regmap_read(pdata->bq->regmap, BQ25703_OTG_CURRENT, &reg); 31 + if (ret) 32 + return ret; 33 + return FIELD_GET(BQ25703_OTG_CUR_MASK, reg) * BQ25703_OTG_CUR_STEP_UA; 34 + } 35 + 36 + /* 37 + * Check if the minimum current and maximum current requested are 38 + * sane values, then set the register accordingly. 39 + */ 40 + static int bq25703_vbus_set_cur_limit(struct regulator_dev *rdev, 41 + int min_uA, int max_uA) 42 + { 43 + struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev); 44 + unsigned int reg; 45 + 46 + if ((min_uA > BQ25703_OTG_CUR_MAX_UA) || (max_uA < 0)) 47 + return -EINVAL; 48 + 49 + reg = (max_uA / BQ25703_OTG_CUR_STEP_UA); 50 + 51 + /* Catch rounding errors since our step is 50000uA. */ 52 + if ((reg * BQ25703_OTG_CUR_STEP_UA) < min_uA) 53 + return -EINVAL; 54 + 55 + return regmap_write(pdata->bq->regmap, BQ25703_OTG_CURRENT, 56 + FIELD_PREP(BQ25703_OTG_CUR_MASK, reg)); 57 + } 58 + 59 + static int bq25703_vbus_enable(struct regulator_dev *rdev) 60 + { 61 + struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev); 62 + 63 + if (pdata->otg_en_gpio) 64 + gpiod_set_value_cansleep(pdata->otg_en_gpio, 1); 65 + return regulator_enable_regmap(rdev); 66 + } 67 + 68 + static int bq25703_vbus_disable(struct regulator_dev *rdev) 69 + { 70 + struct bq257xx_reg_data *pdata = rdev_get_drvdata(rdev); 71 + 72 + if (pdata->otg_en_gpio) 73 + gpiod_set_value_cansleep(pdata->otg_en_gpio, 0); 74 + return regulator_disable_regmap(rdev); 75 + } 76 + 77 + static const struct regulator_ops bq25703_vbus_ops = { 78 + .enable = bq25703_vbus_enable, 79 + .disable = bq25703_vbus_disable, 80 + .is_enabled = regulator_is_enabled_regmap, 81 + .list_voltage = regulator_list_voltage_linear, 82 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 83 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 84 + .get_current_limit = bq25703_vbus_get_cur_limit, 85 + .set_current_limit = bq25703_vbus_set_cur_limit, 86 + }; 87 + 88 + static const struct regulator_desc bq25703_vbus_desc = { 89 + .name = "vbus", 90 + .of_match = of_match_ptr("vbus"), 91 + .regulators_node = of_match_ptr("regulators"), 92 + .type = REGULATOR_VOLTAGE, 93 + .owner = THIS_MODULE, 94 + .ops = &bq25703_vbus_ops, 95 + .min_uV = BQ25703_OTG_VOLT_MIN_UV, 96 + .uV_step = BQ25703_OTG_VOLT_STEP_UV, 97 + .n_voltages = BQ25703_OTG_VOLT_NUM_VOLT, 98 + .enable_mask = BQ25703_EN_OTG_MASK, 99 + .enable_reg = BQ25703_CHARGE_OPTION_3, 100 + .enable_val = BQ25703_EN_OTG_MASK, 101 + .disable_val = 0, 102 + .vsel_reg = BQ25703_OTG_VOLT, 103 + .vsel_mask = BQ25703_OTG_VOLT_MASK, 104 + }; 105 + 106 + /* Get optional GPIO for OTG regulator enable. */ 107 + static void bq257xx_reg_dt_parse_gpio(struct platform_device *pdev) 108 + { 109 + struct device_node *child, *subchild; 110 + struct bq257xx_reg_data *pdata = platform_get_drvdata(pdev); 111 + 112 + child = of_get_child_by_name(pdev->dev.of_node, 113 + pdata->desc.regulators_node); 114 + if (!child) 115 + return; 116 + 117 + subchild = of_get_child_by_name(child, pdata->desc.of_match); 118 + if (!subchild) 119 + return; 120 + 121 + of_node_put(child); 122 + 123 + pdata->otg_en_gpio = devm_fwnode_gpiod_get_index(&pdev->dev, 124 + of_fwnode_handle(subchild), 125 + "enable", 0, 126 + GPIOD_OUT_LOW, 127 + pdata->desc.of_match); 128 + 129 + of_node_put(subchild); 130 + 131 + if (IS_ERR(pdata->otg_en_gpio)) { 132 + dev_err(&pdev->dev, "Error getting enable gpio: %ld\n", 133 + PTR_ERR(pdata->otg_en_gpio)); 134 + return; 135 + } 136 + } 137 + 138 + static int bq257xx_regulator_probe(struct platform_device *pdev) 139 + { 140 + struct device *dev = &pdev->dev; 141 + struct bq257xx_device *bq = dev_get_drvdata(pdev->dev.parent); 142 + struct bq257xx_reg_data *pdata; 143 + struct device_node *np = dev->of_node; 144 + struct regulator_config cfg = {}; 145 + 146 + pdev->dev.of_node = pdev->dev.parent->of_node; 147 + pdev->dev.of_node_reused = true; 148 + 149 + pdata = devm_kzalloc(&pdev->dev, sizeof(struct bq257xx_reg_data), GFP_KERNEL); 150 + if (!pdata) 151 + return -ENOMEM; 152 + 153 + pdata->bq = bq; 154 + pdata->desc = bq25703_vbus_desc; 155 + 156 + platform_set_drvdata(pdev, pdata); 157 + bq257xx_reg_dt_parse_gpio(pdev); 158 + 159 + cfg.dev = &pdev->dev; 160 + cfg.driver_data = pdata; 161 + cfg.of_node = np; 162 + cfg.regmap = dev_get_regmap(pdev->dev.parent, NULL); 163 + if (!cfg.regmap) 164 + return -ENODEV; 165 + 166 + pdata->bq257xx_reg = devm_regulator_register(dev, &pdata->desc, &cfg); 167 + if (IS_ERR(pdata->bq257xx_reg)) { 168 + return dev_err_probe(&pdev->dev, PTR_ERR(pdata->bq257xx_reg), 169 + "error registering bq257xx regulator"); 170 + } 171 + 172 + return 0; 173 + } 174 + 175 + static struct platform_driver bq257xx_reg_driver = { 176 + .driver = { 177 + .name = "bq257xx-regulator", 178 + }, 179 + .probe = bq257xx_regulator_probe, 180 + }; 181 + 182 + module_platform_driver(bq257xx_reg_driver); 183 + 184 + MODULE_DESCRIPTION("bq257xx regulator driver"); 185 + MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); 186 + MODULE_LICENSE("GPL");