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