mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
regulator: Updates for v6.14
This was a very quiet release, aside from some smaller improvements we
have:
- Support for power budgeting on regulators, initially targeted at some
still in review support for PSE controllers but generally useful.
- Support for error interrupts from ROHM BD96801 devices.
- Support for NXP PCA9452.
-----BEGIN PGP SIGNATURE-----
iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmeOYVoACgkQJNaLcl1U
h9D5tAf/RHg2j8OHQlTIjx8nebxIr8RRVmI5ltIlOA6biHsRzIHxOt7HjBaGTl78
qnpOJ8X+JUP5BP0F1n792e5f1HJykyIJA6nQnZfLIeUnLU2KsRPf1hJzDXgIvIoU
1cWuMe0j7oI0+DZYYY5G1AHw1n1J4M3HfXQyuWhfz1hlZTqBAWQSdkRyBp6Yyyth
m6XoAf72ADaKHB0GU6jbdNJJyO8D7rlwk0j6nlm0qoAIi52Se2ZeeJH707Wd/zGI
G3RF4MLkNUzOmzi3hJkhLILG5XwEQiu4pZGgOnYK6AdbxV8fWwq8PNzMqq/lb4Sl
A17Ib8eAPUPfVfUctAvx9DnGnaJKBw==
=Ttps
-----END PGP SIGNATURE-----
Merge tag 'regulator-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"This was a very quiet release, aside from some smaller improvements we
have:
- Support for power budgeting on regulators, initially targeted at
some still in review support for PSE controllers but generally
useful
- Support for error interrupts from ROHM BD96801 devices
- Support for NXP PCA9452"
* tag 'regulator-v6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator:
regulator: dt-bindings: Add regulator-power-budget-milliwatt property
regulator: Add support for power budget
regulator: core: Resolve supply using of_node from regulator_config
regulator: of: Implement the unwind path of of_regulator_match()
regulator: tps65219: Remove debugging helper function
regulator: tps65219: Remove MODULE_ALIAS
regulator: tps65219: Update driver name
regulator: tps65219: Use dev_err_probe() instead of dev_err()
regulator: dt-bindings: mt6315: Drop regulator-compatible property
regulator: pca9450: Add PMIC pca9452 support
regulator: dt-bindings: pca9450: Add pca9452 support
regulator: pca9450: Use dev_err_probe() to simplify code
regulator: pca9450: add enable_value for all bucks
regulator: bd96801: Add ERRB IRQ
This commit is contained in:
commit
7b081a74c0
|
|
@ -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>;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ properties:
|
|||
- nxp,pca9450b
|
||||
- nxp,pca9450c
|
||||
- nxp,pca9451a
|
||||
- nxp,pca9452
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ properties:
|
|||
regulator-input-current-limit-microamp:
|
||||
description: maximum input current regulator allows
|
||||
|
||||
regulator-power-budget-milliwatt:
|
||||
description: power budget of the regulator
|
||||
|
||||
regulator-always-on:
|
||||
description: boolean, regulator should never be disabled
|
||||
type: boolean
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -917,6 +917,26 @@ static ssize_t bypass_show(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RO(bypass);
|
||||
|
||||
static ssize_t power_budget_milliwatt_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", rdev->constraints->pw_budget_mW);
|
||||
}
|
||||
static DEVICE_ATTR_RO(power_budget_milliwatt);
|
||||
|
||||
static ssize_t power_requested_milliwatt_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct regulator_dev *rdev = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "%d\n", rdev->pw_requested_mW);
|
||||
}
|
||||
static DEVICE_ATTR_RO(power_requested_milliwatt);
|
||||
|
||||
#define REGULATOR_ERROR_ATTR(name, bit) \
|
||||
static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
|
|
@ -1149,6 +1169,10 @@ static void print_constraints_debug(struct regulator_dev *rdev)
|
|||
if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
|
||||
count += scnprintf(buf + count, len - count, "standby ");
|
||||
|
||||
if (constraints->pw_budget_mW)
|
||||
count += scnprintf(buf + count, len - count, "%d mW budget",
|
||||
constraints->pw_budget_mW);
|
||||
|
||||
if (!count)
|
||||
count = scnprintf(buf, len, "no parameters");
|
||||
else
|
||||
|
|
@ -1627,6 +1651,9 @@ static int set_machine_constraints(struct regulator_dev *rdev)
|
|||
rdev->last_off = ktime_get();
|
||||
}
|
||||
|
||||
if (!rdev->constraints->pw_budget_mW)
|
||||
rdev->constraints->pw_budget_mW = INT_MAX;
|
||||
|
||||
print_constraints(rdev);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1936,6 +1963,20 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
|
|||
return dev ? dev_to_rdev(dev) : NULL;
|
||||
}
|
||||
|
||||
static struct regulator_dev *regulator_dt_lookup(struct device *dev,
|
||||
const char *supply)
|
||||
{
|
||||
struct regulator_dev *r = NULL;
|
||||
|
||||
if (dev_of_node(dev)) {
|
||||
r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
|
||||
if (PTR_ERR(r) == -ENODEV)
|
||||
r = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_dev_lookup - lookup a regulator device.
|
||||
* @dev: device for regulator "consumer".
|
||||
|
|
@ -1960,16 +2001,9 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
|
|||
regulator_supply_alias(&dev, &supply);
|
||||
|
||||
/* first do a dt based lookup */
|
||||
if (dev_of_node(dev)) {
|
||||
r = of_regulator_dev_lookup(dev, dev_of_node(dev), supply);
|
||||
if (!IS_ERR(r))
|
||||
return r;
|
||||
if (PTR_ERR(r) == -EPROBE_DEFER)
|
||||
return r;
|
||||
|
||||
if (PTR_ERR(r) == -ENODEV)
|
||||
r = NULL;
|
||||
}
|
||||
r = regulator_dt_lookup(dev, supply);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* if not found, try doing it non-dt way */
|
||||
if (dev)
|
||||
|
|
@ -2015,7 +2049,17 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
|
|||
if (rdev->supply)
|
||||
return 0;
|
||||
|
||||
r = regulator_dev_lookup(dev, rdev->supply_name);
|
||||
/* first do a dt based lookup on the node described in the virtual
|
||||
* device.
|
||||
*/
|
||||
r = regulator_dt_lookup(&rdev->dev, rdev->supply_name);
|
||||
|
||||
/* If regulator not found use usual search path in the parent
|
||||
* device.
|
||||
*/
|
||||
if (!r)
|
||||
r = regulator_dev_lookup(dev, rdev->supply_name);
|
||||
|
||||
if (IS_ERR(r)) {
|
||||
ret = PTR_ERR(r);
|
||||
|
||||
|
|
@ -4584,6 +4628,87 @@ int regulator_get_current_limit(struct regulator *regulator)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_get_current_limit);
|
||||
|
||||
/**
|
||||
* regulator_get_unclaimed_power_budget - get regulator unclaimed power budget
|
||||
* @regulator: regulator source
|
||||
*
|
||||
* Return: Unclaimed power budget of the regulator in mW.
|
||||
*/
|
||||
int regulator_get_unclaimed_power_budget(struct regulator *regulator)
|
||||
{
|
||||
return regulator->rdev->constraints->pw_budget_mW -
|
||||
regulator->rdev->pw_requested_mW;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_get_unclaimed_power_budget);
|
||||
|
||||
/**
|
||||
* regulator_request_power_budget - request power budget on a regulator
|
||||
* @regulator: regulator source
|
||||
* @pw_req: Power requested
|
||||
*
|
||||
* Return: 0 on success or a negative error number on failure.
|
||||
*/
|
||||
int regulator_request_power_budget(struct regulator *regulator,
|
||||
unsigned int pw_req)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
int ret = 0, pw_tot_req;
|
||||
|
||||
regulator_lock(rdev);
|
||||
if (rdev->supply) {
|
||||
ret = regulator_request_power_budget(rdev->supply, pw_req);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pw_tot_req = rdev->pw_requested_mW + pw_req;
|
||||
if (pw_tot_req > rdev->constraints->pw_budget_mW) {
|
||||
rdev_warn(rdev, "power requested %d mW out of budget %d mW",
|
||||
pw_req,
|
||||
rdev->constraints->pw_budget_mW - rdev->pw_requested_mW);
|
||||
regulator_notifier_call_chain(rdev,
|
||||
REGULATOR_EVENT_OVER_CURRENT_WARN,
|
||||
NULL);
|
||||
ret = -ERANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rdev->pw_requested_mW = pw_tot_req;
|
||||
out:
|
||||
regulator_unlock(rdev);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_request_power_budget);
|
||||
|
||||
/**
|
||||
* regulator_free_power_budget - free power budget on a regulator
|
||||
* @regulator: regulator source
|
||||
* @pw: Power to be released.
|
||||
*
|
||||
* Return: Power budget of the regulator in mW.
|
||||
*/
|
||||
void regulator_free_power_budget(struct regulator *regulator,
|
||||
unsigned int pw)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
int pw_tot_req;
|
||||
|
||||
regulator_lock(rdev);
|
||||
if (rdev->supply)
|
||||
regulator_free_power_budget(rdev->supply, pw);
|
||||
|
||||
pw_tot_req = rdev->pw_requested_mW - pw;
|
||||
if (pw_tot_req >= 0)
|
||||
rdev->pw_requested_mW = pw_tot_req;
|
||||
else
|
||||
rdev_warn(rdev,
|
||||
"too much power freed %d mW (already requested %d mW)",
|
||||
pw, rdev->pw_requested_mW);
|
||||
|
||||
regulator_unlock(rdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_free_power_budget);
|
||||
|
||||
/**
|
||||
* regulator_set_mode - set regulator operating mode
|
||||
* @regulator: regulator source
|
||||
|
|
@ -5222,6 +5347,8 @@ static struct attribute *regulator_dev_attrs[] = {
|
|||
&dev_attr_suspend_standby_mode.attr,
|
||||
&dev_attr_suspend_mem_mode.attr,
|
||||
&dev_attr_suspend_disk_mode.attr,
|
||||
&dev_attr_power_budget_milliwatt.attr,
|
||||
&dev_attr_power_requested_milliwatt.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -5303,6 +5430,10 @@ static umode_t regulator_attr_is_visible(struct kobject *kobj,
|
|||
attr == &dev_attr_suspend_disk_mode.attr)
|
||||
return ops->set_suspend_mode ? mode : 0;
|
||||
|
||||
if (attr == &dev_attr_power_budget_milliwatt.attr ||
|
||||
attr == &dev_attr_power_requested_milliwatt.attr)
|
||||
return rdev->constraints->pw_budget_mW != INT_MAX ? mode : 0;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ static int of_get_regulation_constraints(struct device *dev,
|
|||
if (constraints->min_uA != constraints->max_uA)
|
||||
constraints->valid_ops_mask |= REGULATOR_CHANGE_CURRENT;
|
||||
|
||||
if (!of_property_read_u32(np, "regulator-power-budget-milliwatt", &pval))
|
||||
constraints->pw_budget_mW = pval;
|
||||
|
||||
constraints->boot_on = of_property_read_bool(np, "regulator-boot-on");
|
||||
constraints->always_on = of_property_read_bool(np, "regulator-always-on");
|
||||
if (!constraints->always_on) /* status change should be possible. */
|
||||
|
|
@ -446,7 +449,7 @@ int of_regulator_match(struct device *dev, struct device_node *node,
|
|||
"failed to parse DT for regulator %pOFn\n",
|
||||
child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
goto err_put;
|
||||
}
|
||||
match->of_node = of_node_get(child);
|
||||
count++;
|
||||
|
|
@ -455,6 +458,18 @@ int of_regulator_match(struct device *dev, struct device_node *node,
|
|||
}
|
||||
|
||||
return count;
|
||||
|
||||
err_put:
|
||||
for (i = 0; i < num_matches; i++) {
|
||||
struct of_regulator_match *match = &matches[i];
|
||||
|
||||
match->init_data = NULL;
|
||||
if (match->of_node) {
|
||||
of_node_put(match->of_node);
|
||||
match->of_node = NULL;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_regulator_match);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = ®ulator_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);
|
||||
|
|
|
|||
|
|
@ -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, ®ulators[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");
|
||||
|
|
|
|||
|
|
@ -233,6 +233,11 @@ int regulator_sync_voltage(struct regulator *regulator);
|
|||
int regulator_set_current_limit(struct regulator *regulator,
|
||||
int min_uA, int max_uA);
|
||||
int regulator_get_current_limit(struct regulator *regulator);
|
||||
int regulator_get_unclaimed_power_budget(struct regulator *regulator);
|
||||
int regulator_request_power_budget(struct regulator *regulator,
|
||||
unsigned int pw_req);
|
||||
void regulator_free_power_budget(struct regulator *regulator,
|
||||
unsigned int pw);
|
||||
|
||||
int regulator_set_mode(struct regulator *regulator, unsigned int mode);
|
||||
unsigned int regulator_get_mode(struct regulator *regulator);
|
||||
|
|
@ -526,6 +531,22 @@ static inline int regulator_get_current_limit(struct regulator *regulator)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int regulator_get_unclaimed_power_budget(struct regulator *regulator)
|
||||
{
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
static inline int regulator_request_power_budget(struct regulator *regulator,
|
||||
unsigned int pw_req)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void regulator_free_power_budget(struct regulator *regulator,
|
||||
unsigned int pw)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int regulator_set_mode(struct regulator *regulator,
|
||||
unsigned int mode)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -656,6 +656,8 @@ struct regulator_dev {
|
|||
int cached_err;
|
||||
bool use_cached_err;
|
||||
spinlock_t err_lock;
|
||||
|
||||
int pw_requested_mW;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ struct notification_limit {
|
|||
* @min_uA: Smallest current consumers may set.
|
||||
* @max_uA: Largest current consumers may set.
|
||||
* @ilim_uA: Maximum input current.
|
||||
* @pw_budget_mW: Power budget for the regulator in mW.
|
||||
* @system_load: Load that isn't captured by any consumer requests.
|
||||
*
|
||||
* @over_curr_limits: Limits for acting on over current.
|
||||
|
|
@ -185,6 +186,7 @@ struct regulation_constraints {
|
|||
int max_uA;
|
||||
int ilim_uA;
|
||||
|
||||
int pw_budget_mW;
|
||||
int system_load;
|
||||
|
||||
/* used for coupled regulators */
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ enum pca9450_chip_type {
|
|||
PCA9450_TYPE_PCA9450A = 0,
|
||||
PCA9450_TYPE_PCA9450BC,
|
||||
PCA9450_TYPE_PCA9451A,
|
||||
PCA9450_TYPE_PCA9452,
|
||||
PCA9450_TYPE_AMOUNT,
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user