Merge remote-tracking branch 'regulator/for-6.14' into regulator-next

This commit is contained in:
Mark Brown 2024-12-19 14:24:39 +00:00
commit 8100d74e2e
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
6 changed files with 187 additions and 101 deletions

View File

@ -35,10 +35,6 @@ properties:
$ref: regulator.yaml#
unevaluatedProperties: false
properties:
regulator-compatible:
pattern: "^vbuck[1-4]$"
additionalProperties: false
required:
@ -56,7 +52,6 @@ examples:
regulators {
vbuck1 {
regulator-compatible = "vbuck1";
regulator-min-microvolt = <300000>;
regulator-max-microvolt = <1193750>;
regulator-enable-ramp-delay = <256>;
@ -64,7 +59,6 @@ examples:
};
vbuck3 {
regulator-compatible = "vbuck3";
regulator-min-microvolt = <300000>;
regulator-max-microvolt = <1193750>;
regulator-enable-ramp-delay = <256>;

View File

@ -29,6 +29,7 @@ properties:
- nxp,pca9450b
- nxp,pca9450c
- nxp,pca9451a
- nxp,pca9452
reg:
maxItems: 1

View File

@ -5,12 +5,7 @@
/*
* This version of the "BD86801 scalable PMIC"'s driver supports only very
* basic set of the PMIC features. Most notably, there is no support for
* the ERRB interrupt and the configurations which should be done when the
* PMIC is in STBY mode.
*
* Supporting the ERRB interrupt would require dropping the regmap-IRQ
* usage or working around (or accepting a presense of) a naming conflict
* in debugFS IRQs.
* the configurations which should be done when the PMIC is in STBY mode.
*
* Being able to reliably do the configurations like changing the
* regulator safety limits (like limits for the over/under -voltages, over
@ -22,16 +17,14 @@
* be the need to configure these safety limits. Hence it's not simple to
* come up with a generic solution.
*
* Users who require the ERRB handling and STBY state configurations can
* have a look at the original RFC:
* Users who require the STBY state configurations can have a look at the
* original RFC:
* https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/
* which implements a workaround to debugFS naming conflict and some of
* the safety limit configurations - but leaves the state change handling
* and synchronization to be implemented.
* which implements some of the safety limit configurations - but leaves the
* state change handling and synchronization to be implemented.
*
* It would be great to hear (and receive a patch!) if you implement the
* STBY configuration support or a proper fix to the debugFS naming
* conflict in your downstream driver ;)
* STBY configuration support in your downstream driver ;)
*/
#include <linux/cleanup.h>
@ -728,6 +721,95 @@ static int initialize_pmic_data(struct device *dev,
return 0;
}
static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid,
unsigned long *dev_mask)
{
int i;
for (i = 0; i < rid->num_states; i++) {
rid->states[i].notifs = REGULATOR_EVENT_FAIL;
rid->states[i].errors = REGULATOR_ERROR_FAIL;
*dev_mask |= BIT(i);
}
return 0;
}
static int bd96801_rdev_errb_irqs(struct platform_device *pdev,
struct regulator_dev *rdev)
{
int i;
void *retp;
static const char * const single_out_errb_irqs[] = {
"bd96801-%s-pvin-err", "bd96801-%s-ovp-err",
"bd96801-%s-uvp-err", "bd96801-%s-shdn-err",
};
for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) {
struct regulator_irq_desc id = {
.map_event = bd96801_map_event_all,
.irq_off_ms = 1000,
};
struct regulator_dev *rdev_arr[1];
char tmp[255];
int irq;
snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name);
tmp[254] = 0;
id.name = tmp;
irq = platform_get_irq_byname(pdev, tmp);
if (irq < 0)
continue;
rdev_arr[0] = rdev;
retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
REGULATOR_ERROR_FAIL, NULL,
rdev_arr, 1);
if (IS_ERR(retp))
return PTR_ERR(retp);
}
return 0;
}
static int bd96801_global_errb_irqs(struct platform_device *pdev,
struct regulator_dev **rdev, int num_rdev)
{
int i, num_irqs;
void *retp;
static const char * const global_errb_irqs[] = {
"bd96801-otp-err", "bd96801-dbist-err", "bd96801-eep-err",
"bd96801-abist-err", "bd96801-prstb-err", "bd96801-drmoserr1",
"bd96801-drmoserr2", "bd96801-slave-err", "bd96801-vref-err",
"bd96801-tsd", "bd96801-uvlo-err", "bd96801-ovlo-err",
"bd96801-osc-err", "bd96801-pon-err", "bd96801-poff-err",
"bd96801-cmd-shdn-err", "bd96801-int-shdn-err"
};
num_irqs = ARRAY_SIZE(global_errb_irqs);
for (i = 0; i < num_irqs; i++) {
int irq;
struct regulator_irq_desc id = {
.name = global_errb_irqs[i],
.map_event = bd96801_map_event_all,
.irq_off_ms = 1000,
};
irq = platform_get_irq_byname(pdev, global_errb_irqs[i]);
if (irq < 0)
continue;
retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0,
REGULATOR_ERROR_FAIL, NULL,
rdev, num_rdev);
if (IS_ERR(retp))
return PTR_ERR(retp);
}
return 0;
}
static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
struct bd96801_pmic_data *pdata,
struct bd96801_irqinfo *iinfo,
@ -783,11 +865,10 @@ static int bd96801_rdev_intb_irqs(struct platform_device *pdev,
return 0;
}
static int bd96801_probe(struct platform_device *pdev)
{
struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS];
struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS];
struct bd96801_regulator_data *rdesc;
struct regulator_config config = {};
int ldo_errs_arr[BD96801_NUM_LDOS];
@ -795,6 +876,7 @@ static int bd96801_probe(struct platform_device *pdev)
int temp_notif_ldos = 0;
struct device *parent;
int i, ret;
bool use_errb;
void *retp;
parent = pdev->dev.parent;
@ -819,6 +901,13 @@ static int bd96801_probe(struct platform_device *pdev)
config.regmap = pdata->regmap;
config.dev = parent;
ret = of_property_match_string(pdev->dev.parent->of_node,
"interrupt-names", "errb");
if (ret < 0)
use_errb = false;
else
use_errb = true;
ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc,
BD96801_NUM_REGULATORS);
if (ret)
@ -837,6 +926,7 @@ static int bd96801_probe(struct platform_device *pdev)
rdesc[i].desc.name);
return PTR_ERR(rdev);
}
all_rdevs[i] = rdev;
/*
* LDOs don't have own temperature monitoring. If temperature
* notification was requested for this LDO from DT then we will
@ -856,6 +946,12 @@ static int bd96801_probe(struct platform_device *pdev)
if (ret)
return ret;
}
/* Register per regulator ERRB notifiers */
if (use_errb) {
ret = bd96801_rdev_errb_irqs(pdev, rdev);
if (ret)
return ret;
}
}
if (temp_notif_ldos) {
int irq;
@ -877,6 +973,10 @@ static int bd96801_probe(struct platform_device *pdev)
return PTR_ERR(retp);
}
if (use_errb)
return bd96801_global_errb_irqs(pdev, all_rdevs,
ARRAY_SIZE(all_rdevs));
return 0;
}

View File

@ -247,6 +247,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.ramp_mask = BUCK1_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
.n_ramp_values = ARRAY_SIZE(pca9450_dvs_buck_ramp_table),
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
.of_parse_cb = pca9450_set_dvs_levels,
},
@ -272,6 +273,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK2_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ_STBYREQ,
.ramp_reg = PCA9450_REG_BUCK2CTRL,
.ramp_mask = BUCK2_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
@ -301,6 +303,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK3OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK3CTRL,
.enable_mask = BUCK3_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.ramp_reg = PCA9450_REG_BUCK3CTRL,
.ramp_mask = BUCK3_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
@ -330,6 +333,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK4OUT_MASK,
.enable_reg = PCA9450_REG_BUCK4CTRL,
.enable_mask = BUCK4_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -348,6 +352,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK5OUT_MASK,
.enable_reg = PCA9450_REG_BUCK5CTRL,
.enable_mask = BUCK5_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -366,6 +371,7 @@ static const struct pca9450_regulator_desc pca9450a_regulators[] = {
.vsel_mask = BUCK6OUT_MASK,
.enable_reg = PCA9450_REG_BUCK6CTRL,
.enable_mask = BUCK6_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -481,6 +487,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK1OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK1CTRL,
.enable_mask = BUCK1_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.ramp_reg = PCA9450_REG_BUCK1CTRL,
.ramp_mask = BUCK1_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
@ -510,6 +517,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK2OUT_DVS0_MASK,
.enable_reg = PCA9450_REG_BUCK2CTRL,
.enable_mask = BUCK2_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ_STBYREQ,
.ramp_reg = PCA9450_REG_BUCK2CTRL,
.ramp_mask = BUCK2_RAMP_MASK,
.ramp_delay_table = pca9450_dvs_buck_ramp_table,
@ -539,6 +547,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK4OUT_MASK,
.enable_reg = PCA9450_REG_BUCK4CTRL,
.enable_mask = BUCK4_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -557,6 +566,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK5OUT_MASK,
.enable_reg = PCA9450_REG_BUCK5CTRL,
.enable_mask = BUCK5_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -575,6 +585,7 @@ static const struct pca9450_regulator_desc pca9450bc_regulators[] = {
.vsel_mask = BUCK6OUT_MASK,
.enable_reg = PCA9450_REG_BUCK6CTRL,
.enable_mask = BUCK6_ENMODE_MASK,
.enable_val = BUCK_ENMODE_ONREQ,
.owner = THIS_MODULE,
},
},
@ -804,6 +815,24 @@ static const struct pca9450_regulator_desc pca9451a_regulators[] = {
.owner = THIS_MODULE,
},
},
{
.desc = {
.name = "ldo3",
.of_match = of_match_ptr("LDO3"),
.regulators_node = of_match_ptr("regulators"),
.id = PCA9450_LDO3,
.ops = &pca9450_ldo_regulator_ops,
.type = REGULATOR_VOLTAGE,
.n_voltages = PCA9450_LDO3_VOLTAGE_NUM,
.linear_ranges = pca9450_ldo34_volts,
.n_linear_ranges = ARRAY_SIZE(pca9450_ldo34_volts),
.vsel_reg = PCA9450_REG_LDO3CTRL,
.vsel_mask = LDO3OUT_MASK,
.enable_reg = PCA9450_REG_LDO3CTRL,
.enable_mask = LDO3_EN_MASK,
.owner = THIS_MODULE,
},
},
{
.desc = {
.name = "ldo4",
@ -905,6 +934,7 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450->rcnt = ARRAY_SIZE(pca9450bc_regulators);
break;
case PCA9450_TYPE_PCA9451A:
case PCA9450_TYPE_PCA9452:
regulator_desc = pca9451a_regulators;
pca9450->rcnt = ARRAY_SIZE(pca9451a_regulators);
break;
@ -921,25 +951,21 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450->regmap = devm_regmap_init_i2c(i2c,
&pca9450_regmap_config);
if (IS_ERR(pca9450->regmap)) {
dev_err(&i2c->dev, "regmap initialization failed\n");
return PTR_ERR(pca9450->regmap);
}
if (IS_ERR(pca9450->regmap))
return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->regmap),
"regmap initialization failed\n");
ret = regmap_read(pca9450->regmap, PCA9450_REG_DEV_ID, &device_id);
if (ret) {
dev_err(&i2c->dev, "Read device id error\n");
return ret;
}
if (ret)
return dev_err_probe(&i2c->dev, ret, "Read device id error\n");
/* Check your board and dts for match the right pmic */
if (((device_id >> 4) != 0x1 && type == PCA9450_TYPE_PCA9450A) ||
((device_id >> 4) != 0x3 && type == PCA9450_TYPE_PCA9450BC) ||
((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A)) {
dev_err(&i2c->dev, "Device id(%x) mismatched\n",
device_id >> 4);
return -EINVAL;
}
((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9451A) ||
((device_id >> 4) != 0x9 && type == PCA9450_TYPE_PCA9452))
return dev_err_probe(&i2c->dev, -EINVAL,
"Device id(%x) mismatched\n", device_id >> 4);
for (i = 0; i < pca9450->rcnt; i++) {
const struct regulator_desc *desc;
@ -949,17 +975,16 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
r = &regulator_desc[i];
desc = &r->desc;
if (type == PCA9450_TYPE_PCA9451A && !strcmp(desc->name, "ldo3"))
continue;
config.regmap = pca9450->regmap;
config.dev = pca9450->dev;
rdev = devm_regulator_register(pca9450->dev, desc, &config);
if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
dev_err(pca9450->dev,
"Failed to register regulator(%s): %d\n",
desc->name, ret);
return ret;
}
if (IS_ERR(rdev))
return dev_err_probe(pca9450->dev, PTR_ERR(rdev),
"Failed to register regulator(%s)\n", desc->name);
}
if (pca9450->irq) {
@ -967,29 +992,24 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
pca9450_irq_handler,
(IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
"pca9450-irq", pca9450);
if (ret != 0) {
dev_err(pca9450->dev, "Failed to request IRQ: %d\n",
pca9450->irq);
return ret;
}
if (ret != 0)
return dev_err_probe(pca9450->dev, ret, "Failed to request IRQ: %d\n",
pca9450->irq);
/* Unmask all interrupt except PWRON/WDOG/RSVD */
ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_INT1_MSK,
IRQ_VR_FLT1 | IRQ_VR_FLT2 | IRQ_LOWVSYS |
IRQ_THERM_105 | IRQ_THERM_125,
IRQ_PWRON | IRQ_WDOGB | IRQ_RSVD);
if (ret) {
dev_err(&i2c->dev, "Unmask irq error\n");
return ret;
}
if (ret)
return dev_err_probe(&i2c->dev, ret, "Unmask irq error\n");
}
/* Clear PRESET_EN bit in BUCK123_DVS to use DVS registers */
ret = regmap_clear_bits(pca9450->regmap, PCA9450_REG_BUCK123_DVS,
BUCK123_PRESET_EN);
if (ret) {
dev_err(&i2c->dev, "Failed to clear PRESET_EN bit: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(&i2c->dev, ret, "Failed to clear PRESET_EN bit\n");
if (of_property_read_bool(i2c->dev.of_node, "nxp,wdog_b-warm-reset"))
reset_ctrl = WDOG_B_CFG_WARM;
@ -999,20 +1019,16 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
/* Set reset behavior on assertion of WDOG_B signal */
ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_RESET_CTRL,
WDOG_B_CFG_MASK, reset_ctrl);
if (ret) {
dev_err(&i2c->dev, "Failed to set WDOG_B reset behavior\n");
return ret;
}
if (ret)
return dev_err_probe(&i2c->dev, ret, "Failed to set WDOG_B reset behavior\n");
if (of_property_read_bool(i2c->dev.of_node, "nxp,i2c-lt-enable")) {
/* Enable I2C Level Translator */
ret = regmap_update_bits(pca9450->regmap, PCA9450_REG_CONFIG2,
I2C_LT_MASK, I2C_LT_ON_STANDBY_RUN);
if (ret) {
dev_err(&i2c->dev,
"Failed to enable I2C level translator\n");
return ret;
}
if (ret)
return dev_err_probe(&i2c->dev, ret,
"Failed to enable I2C level translator\n");
}
/*
@ -1022,10 +1038,9 @@ static int pca9450_i2c_probe(struct i2c_client *i2c)
*/
pca9450->sd_vsel_gpio = gpiod_get_optional(pca9450->dev, "sd-vsel", GPIOD_OUT_HIGH);
if (IS_ERR(pca9450->sd_vsel_gpio)) {
dev_err(&i2c->dev, "Failed to get SD_VSEL GPIO\n");
return PTR_ERR(pca9450->sd_vsel_gpio);
}
if (IS_ERR(pca9450->sd_vsel_gpio))
return dev_err_probe(&i2c->dev, PTR_ERR(pca9450->sd_vsel_gpio),
"Failed to get SD_VSEL GPIO\n");
dev_info(&i2c->dev, "%s probed.\n",
type == PCA9450_TYPE_PCA9450A ? "pca9450a" :
@ -1051,6 +1066,10 @@ static const struct of_device_id pca9450_of_match[] = {
.compatible = "nxp,pca9451a",
.data = (void *)PCA9450_TYPE_PCA9451A,
},
{
.compatible = "nxp,pca9452",
.data = (void *)PCA9450_TYPE_PCA9452,
},
{ }
};
MODULE_DEVICE_TABLE(of, pca9450_of_match);

View File

@ -287,21 +287,6 @@ static irqreturn_t tps65219_regulator_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
static int tps65219_get_rdev_by_name(const char *regulator_name,
struct regulator_dev *rdevtbl[7],
struct regulator_dev **dev)
{
int i;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
if (strcmp(regulator_name, regulators[i].name) == 0) {
*dev = rdevtbl[i];
return 0;
}
}
return -EINVAL;
}
static int tps65219_regulator_probe(struct platform_device *pdev)
{
struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
@ -312,23 +297,18 @@ static int tps65219_regulator_probe(struct platform_device *pdev)
int irq;
struct tps65219_regulator_irq_data *irq_data;
struct tps65219_regulator_irq_type *irq_type;
struct regulator_dev *rdevtbl[7];
config.dev = tps->dev;
config.driver_data = tps;
config.regmap = tps->regmap;
for (i = 0; i < ARRAY_SIZE(regulators); i++) {
dev_dbg(tps->dev, "%s regul i= %d START", __func__, i);
rdev = devm_regulator_register(&pdev->dev, &regulators[i],
&config);
if (IS_ERR(rdev)) {
dev_err(tps->dev, "failed to register %s regulator\n",
regulators[i].name);
return PTR_ERR(rdev);
}
rdevtbl[i] = rdev;
dev_dbg(tps->dev, "%s regul i= %d COMPLETED", __func__, i);
if (IS_ERR(rdev))
return dev_err_probe(tps->dev, PTR_ERR(rdev),
"Failed to register %s regulator\n",
regulators[i].name);
}
irq_data = devm_kmalloc(tps->dev,
@ -348,14 +328,6 @@ static int tps65219_regulator_probe(struct platform_device *pdev)
irq_data[i].dev = tps->dev;
irq_data[i].type = irq_type;
tps65219_get_rdev_by_name(irq_type->regulator_name, rdevtbl, &rdev);
if (IS_ERR(rdev)) {
dev_err(tps->dev, "Failed to get rdev for %s\n",
irq_type->regulator_name);
return -EINVAL;
}
irq_data[i].rdev = rdev;
error = devm_request_threaded_irq(tps->dev, irq, NULL,
tps65219_regulator_irq_handler,
IRQF_ONESHOT,
@ -379,7 +351,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_regulator_id_table);
static struct platform_driver tps65219_regulator_driver = {
.driver = {
.name = "tps65219-pmic",
.name = "tps65219-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = tps65219_regulator_probe,
@ -390,5 +362,4 @@ module_platform_driver(tps65219_regulator_driver);
MODULE_AUTHOR("Jerome Neanne <j-neanne@baylibre.com>");
MODULE_DESCRIPTION("TPS65219 voltage regulator driver");
MODULE_ALIAS("platform:tps65219-pmic");
MODULE_LICENSE("GPL");

View File

@ -10,6 +10,7 @@ enum pca9450_chip_type {
PCA9450_TYPE_PCA9450A = 0,
PCA9450_TYPE_PCA9450BC,
PCA9450_TYPE_PCA9451A,
PCA9450_TYPE_PCA9452,
PCA9450_TYPE_AMOUNT,
};