Commit da968017 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'regulator-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator

Pull regulator updates from Mark Brown:
 "The main updates for this release are around monitoring of regulators,
  largely for error handling purposes. We allow the stream of regulator
  events to be seen by userspace as netlink events and allow system
  integrators to describe individual regulators as system critical with
  information on how long the system is expected to last on error. The
  system level error handling is very much about best effort problem
  mitigation rather than providing something fully robust, the initial
  drive was to provide a mechanism for trying to avoid initiating any
  new writes to flash once we notice the power going out.

  Otherwise it's very quiet, mainly several new Qualcomm devices.

   - Support for marking regulators as system critical and providing
     information on how long the system might last with those regulators
     in a failure state, hooked into the existing critical shutdown
     error handling.

   - Optional support for generating netlink events for events, there
     are use cases for system monitoring UIs and error handling.

   - A command line option to leave unused controllable regulators
     enabled, useful for debugging. We already only disable regulators
     we were explicitly given permission to control.

   - Support for Quacomm MP5496, PM8010 and PM8937"

* tag 'regulator-v6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (31 commits)
  regulator: event: Ensure atomicity for sequence number
  uapi: regulator: Fix typo
  regulator: Reuse LINEAR_RANGE() in REGULATOR_LINEAR_RANGE()
  dt-bindings: regulator: qcom,usb-vbus-regulator: clean up example
  regulator: qcom_smd: Add LDO5 MP5496 regulator
  regulator: qcom-rpmh: add support for pm8010 regulators
  regulator: dt-bindings: qcom,rpmh: add compatible for pm8010
  regulator: qcom-rpmh: extend to support multiple linear voltage ranges
  regulator: wm8350: Convert to platform remove callback returning void
  regulator: virtual: Convert to platform remove callback returning void
  regulator: userspace-consumer: Convert to platform remove callback returning void
  regulator: uniphier: Convert to platform remove callback returning void
  regulator: stm32-vrefbuf: Convert to platform remove callback returning void
  regulator: db8500-prcmu: Convert to platform remove callback returning void
  regulator: bd9571mwv: Convert to platform remove callback returning void
  regulator: arizona-ldo1: Convert to platform remove callback returning void
  regulator: event: Add regulator netlink event support
  regulator: event: Add regulator netlink event support
  regulator: stpmic1: Fix kernel-doc notation warnings
  regulator: palmas: remove redundant initialization of pointer pdata
  ...
parents 83130ff4 1cadc04c
......@@ -5544,6 +5544,13 @@
print every Nth verbose statement, where N is the value
specified.
regulator_ignore_unused
[REGULATOR]
Prevents regulator framework from disabling regulators
that are unused, due no driver claiming them. This may
be useful for debug and development, but should not be
needed on a platform with proper driver support.
relax_domain_level=
[KNL, SMP] Set scheduler's default relax_domain_level.
See Documentation/admin-guide/cgroup-v1/cpusets.rst.
......
......@@ -105,6 +105,8 @@ properties:
description:
Interrupt signaling a critical under-voltage event.
system-critical-regulator: true
required:
- compatible
- regulator-name
......
......@@ -42,6 +42,7 @@ description: |
For PM7325, smps1 - smps8, ldo1 - ldo19
For PM8005, smps1 - smps4
For PM8009, smps1 - smps2, ldo1 - ldo7
For PM8010, ldo1 - ldo7
For PM8150, smps1 - smps10, ldo1 - ldo18
For PM8150L, smps1 - smps8, ldo1 - ldo11, bob, flash, rgb
For PM8350, smps1 - smps12, ldo1 - ldo10
......@@ -68,6 +69,7 @@ properties:
- qcom,pm8005-rpmh-regulators
- qcom,pm8009-rpmh-regulators
- qcom,pm8009-1-rpmh-regulators
- qcom,pm8010-rpmh-regulators
- qcom,pm8150-rpmh-regulators
- qcom,pm8150l-rpmh-regulators
- qcom,pm8350-rpmh-regulators
......@@ -238,6 +240,18 @@ allOf:
"^vdd-l[1-47]-supply$": true
"^vdd-s[1-2]-supply$": true
- if:
properties:
compatible:
enum:
- qcom,pm8010-rpmh-regulators
then:
properties:
vdd-l1-l2-supply: true
vdd-l3-l4-supply: true
patternProperties:
"^vdd-l[5-7]-supply$": true
- if:
properties:
compatible:
......
......@@ -47,6 +47,9 @@ description:
For pm8916, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
l12, l13, l14, l15, l16, l17, l18
For pm8937, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10,
l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23
For pm8941, s1, s2, s3, s4, l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11,
l12, l13, l14, l15, l16, l17, l18, l19, l20, l21, l22, l23, l24, lvs1, lvs2,
lvs3, 5vs1, 5vs2
......@@ -92,6 +95,7 @@ properties:
- qcom,rpm-pm8841-regulators
- qcom,rpm-pm8909-regulators
- qcom,rpm-pm8916-regulators
- qcom,rpm-pm8937-regulators
- qcom,rpm-pm8941-regulators
- qcom,rpm-pm8950-regulators
- qcom,rpm-pm8953-regulators
......
......@@ -22,6 +22,7 @@ properties:
- qcom,pm8841-regulators
- qcom,pm8909-regulators
- qcom,pm8916-regulators
- qcom,pm8937-regulators
- qcom,pm8941-regulators
- qcom,pm8950-regulators
- qcom,pm8994-regulators
......@@ -291,6 +292,24 @@ allOf:
patternProperties:
"^vdd_s[1-3]-supply$": true
- if:
properties:
compatible:
contains:
enum:
- qcom,pm8937-regulators
then:
properties:
vdd_l1_l19-supply: true
vdd_l20_l21-supply: true
vdd_l2_l23-supply: true
vdd_l3-supply: true
vdd_l4_l5_l6_l7_l16-supply: true
vdd_l8_l11_l12_l17_l22-supply: true
vdd_l9_l10_l13_l14_l15_l18-supply: true
patternProperties:
"^vdd_s[1-6]-supply$": true
- if:
properties:
compatible:
......
......@@ -36,10 +36,11 @@ unevaluatedProperties: false
examples:
- |
pm8150b {
pmic {
#address-cells = <1>;
#size-cells = <0>;
pm8150b_vbus: usb-vbus-regulator@1100 {
usb-vbus-regulator@1100 {
compatible = "qcom,pm8150b-vbus-reg";
reg = <0x1100>;
regulator-min-microamp = <500000>;
......
......@@ -114,6 +114,11 @@ properties:
description: Enable pull down resistor when the regulator is disabled.
type: boolean
system-critical-regulator:
description: Set if the regulator is critical to system stability or
functionality.
type: boolean
regulator-over-current-protection:
description: Enable over current protection.
type: boolean
......@@ -181,6 +186,14 @@ properties:
be enabled but limit setting can be omitted. Limit is given as microvolt
offset from voltage set to regulator.
regulator-uv-less-critical-window-ms:
description: Specifies the time window (in milliseconds) following a
critical under-voltage event during which the system can continue to
operate safely while performing less critical operations. This property
provides a defined duration before a more severe reaction to the
under-voltage event is needed, allowing for certain non-urgent actions to
be carried out in preparation for potential power loss.
regulator-temp-protection-kelvin:
description: Set over temperature protection limit. This is a limit where
hardware performs emergency shutdown. Zero can be passed to disable
......
......@@ -56,6 +56,16 @@ config REGULATOR_USERSPACE_CONSUMER
If unsure, say no.
config REGULATOR_NETLINK_EVENTS
bool "Enable support for receiving regulator events via netlink"
depends on NET
help
Enabling this option allows the kernel to broadcast regulator events using
the netlink mechanism. User-space applications can subscribe to these events
for real-time updates on various regulator events.
If unsure, say no.
config REGULATOR_88PG86X
tristate "Marvell 88PG86X voltage regulators"
depends on I2C
......
......@@ -5,6 +5,7 @@
obj-$(CONFIG_REGULATOR) += core.o dummy.o fixed-helper.o helpers.o devres.o irq_helpers.o
obj-$(CONFIG_REGULATOR_NETLINK_EVENTS) += event.o
obj-$(CONFIG_OF) += of_regulator.o
obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
......
......@@ -339,14 +339,12 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
return ret;
}
static int arizona_ldo1_remove(struct platform_device *pdev)
static void arizona_ldo1_remove(struct platform_device *pdev)
{
struct arizona_ldo1 *ldo1 = platform_get_drvdata(pdev);
if (ldo1->ena_gpiod)
gpiod_put(ldo1->ena_gpiod);
return 0;
}
static int madera_ldo1_probe(struct platform_device *pdev)
......@@ -377,7 +375,7 @@ static int madera_ldo1_probe(struct platform_device *pdev)
static struct platform_driver arizona_ldo1_driver = {
.probe = arizona_ldo1_probe,
.remove = arizona_ldo1_remove,
.remove_new = arizona_ldo1_remove,
.driver = {
.name = "arizona-ldo1",
.probe_type = PROBE_FORCE_SYNCHRONOUS,
......@@ -386,7 +384,7 @@ static struct platform_driver arizona_ldo1_driver = {
static struct platform_driver madera_ldo1_driver = {
.probe = madera_ldo1_probe,
.remove = arizona_ldo1_remove,
.remove_new = arizona_ldo1_remove,
.driver = {
.name = "madera-ldo1",
.probe_type = PROBE_FORCE_SYNCHRONOUS,
......
......@@ -260,10 +260,9 @@ static const struct dev_pm_ops bd9571mwv_pm = {
SET_SYSTEM_SLEEP_PM_OPS(bd9571mwv_suspend, bd9571mwv_resume)
};
static int bd9571mwv_regulator_remove(struct platform_device *pdev)
static void bd9571mwv_regulator_remove(struct platform_device *pdev)
{
device_remove_file(&pdev->dev, &dev_attr_backup_mode);
return 0;
}
#define DEV_PM_OPS &bd9571mwv_pm
#else
......@@ -357,7 +356,7 @@ static struct platform_driver bd9571mwv_regulator_driver = {
.pm = DEV_PM_OPS,
},
.probe = bd9571mwv_regulator_probe,
.remove = bd9571mwv_regulator_remove,
.remove_new = bd9571mwv_regulator_remove,
.id_table = bd9571mwv_regulator_id_table,
};
module_platform_driver(bd9571mwv_regulator_driver);
......
......@@ -19,6 +19,7 @@
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/consumer.h>
......@@ -32,6 +33,7 @@
#include "dummy.h"
#include "internal.h"
#include "regnl.h"
static DEFINE_WW_CLASS(regulator_ww_class);
static DEFINE_MUTEX(regulator_nesting_mutex);
......@@ -2918,6 +2920,7 @@ static int _regulator_enable(struct regulator *regulator)
/* Fallthrough on positive return values - already enabled */
}
if (regulator->enable_count == 1)
rdev->use_count++;
return 0;
......@@ -2993,10 +2996,12 @@ static int _regulator_disable(struct regulator *regulator)
lockdep_assert_held_once(&rdev->mutex.base);
if (WARN(rdev->use_count <= 0,
if (WARN(regulator->enable_count == 0,
"unbalanced disables for %s\n", rdev_get_name(rdev)))
return -EIO;
if (regulator->enable_count == 1) {
/* disabling last enable_count from this regulator */
/* are we the last user and permitted to disable ? */
if (rdev->use_count == 1 &&
(rdev->constraints && !rdev->constraints->always_on)) {
......@@ -3025,6 +3030,7 @@ static int _regulator_disable(struct regulator *regulator)
} else if (rdev->use_count > 1) {
rdev->use_count--;
}
}
if (ret == 0)
ret = _regulator_handle_consumer_disable(regulator);
......@@ -4849,7 +4855,23 @@ static int _notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
/* call rdev chain first */
return blocking_notifier_call_chain(&rdev->notifier, event, data);
int ret = blocking_notifier_call_chain(&rdev->notifier, event, data);
if (IS_REACHABLE(CONFIG_REGULATOR_NETLINK_EVENTS)) {
struct device *parent = rdev->dev.parent;
const char *rname = rdev_get_name(rdev);
char name[32];
/* Avoid duplicate debugfs directory names */
if (parent && rname == rdev->desc->name) {
snprintf(name, sizeof(name), "%s-%s", dev_name(parent),
rname);
rname = name;
}
reg_generate_netlink_event(rname, event);
}
return ret;
}
int _regulator_bulk_get(struct device *dev, int num_consumers,
......@@ -5061,6 +5083,41 @@ void regulator_bulk_free(int num_consumers,
}
EXPORT_SYMBOL_GPL(regulator_bulk_free);
/**
* regulator_handle_critical - Handle events for system-critical regulators.
* @rdev: The regulator device.
* @event: The event being handled.
*
* This function handles critical events such as under-voltage, over-current,
* and unknown errors for regulators deemed system-critical. On detecting such
* events, it triggers a hardware protection shutdown with a defined timeout.
*/
static void regulator_handle_critical(struct regulator_dev *rdev,
unsigned long event)
{
const char *reason = NULL;
if (!rdev->constraints->system_critical)
return;
switch (event) {
case REGULATOR_EVENT_UNDER_VOLTAGE:
reason = "System critical regulator: voltage drop detected";
break;
case REGULATOR_EVENT_OVER_CURRENT:
reason = "System critical regulator: over-current detected";
break;
case REGULATOR_EVENT_FAIL:
reason = "System critical regulator: unknown error";
}
if (!reason)
return;
hw_protection_shutdown(reason,
rdev->constraints->uv_less_critical_window_ms);
}
/**
* regulator_notifier_call_chain - call regulator event notifier
* @rdev: regulator source
......@@ -5073,6 +5130,8 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data)
{
regulator_handle_critical(rdev, event);
_notifier_call_chain(rdev, event, data);
return NOTIFY_DONE;
......@@ -6234,6 +6293,14 @@ static int regulator_late_cleanup(struct device *dev, void *data)
return 0;
}
static bool regulator_ignore_unused;
static int __init regulator_ignore_unused_setup(char *__unused)
{
regulator_ignore_unused = true;
return 1;
}
__setup("regulator_ignore_unused", regulator_ignore_unused_setup);
static void regulator_init_complete_work_function(struct work_struct *work)
{
/*
......@@ -6246,6 +6313,15 @@ static void regulator_init_complete_work_function(struct work_struct *work)
class_for_each_device(&regulator_class, NULL, NULL,
regulator_register_resolve_supply);
/*
* For debugging purposes, it may be useful to prevent unused
* regulators from being disabled.
*/
if (regulator_ignore_unused) {
pr_warn("regulator: Not disabling unused regulators\n");
return;
}
/* If we have a full configuration then disable any regulators
* we have permission to change the status for and which are
* not in use or always_on. This is effectively the default
......
......@@ -469,11 +469,9 @@ static int db8500_regulator_probe(struct platform_device *pdev)
return 0;
}
static int db8500_regulator_remove(struct platform_device *pdev)
static void db8500_regulator_remove(struct platform_device *pdev)
{
ux500_regulator_debug_exit();
return 0;
}
static struct platform_driver db8500_regulator_driver = {
......@@ -482,7 +480,7 @@ static struct platform_driver db8500_regulator_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = db8500_regulator_probe,
.remove = db8500_regulator_remove,
.remove_new = db8500_regulator_remove,
};
static int __init db8500_regulator_init(void)
......
// SPDX-License-Identifier: GPL-2.0
/*
* Regulator event over netlink
*
* Author: Naresh Solanki <Naresh.Solanki@9elements.com>
*/
#include <regulator/regulator.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <linux/atomic.h>
#include "regnl.h"
static atomic_t reg_event_seqnum = ATOMIC_INIT(0);
static const struct genl_multicast_group reg_event_mcgrps[] = {
{ .name = REG_GENL_MCAST_GROUP_NAME, },
};
static struct genl_family reg_event_genl_family __ro_after_init = {
.module = THIS_MODULE,
.name = REG_GENL_FAMILY_NAME,
.version = REG_GENL_VERSION,
.maxattr = REG_GENL_ATTR_MAX,
.mcgrps = reg_event_mcgrps,
.n_mcgrps = ARRAY_SIZE(reg_event_mcgrps),
};
int reg_generate_netlink_event(const char *reg_name, u64 event)
{
struct sk_buff *skb;
struct nlattr *attr;
struct reg_genl_event *edata;
void *msg_header;
int size;
/* allocate memory */
size = nla_total_size(sizeof(struct reg_genl_event)) +
nla_total_size(0);
skb = genlmsg_new(size, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
/* add the genetlink message header */
msg_header = genlmsg_put(skb, 0, atomic_inc_return(&reg_event_seqnum),
&reg_event_genl_family, 0, REG_GENL_CMD_EVENT);
if (!msg_header) {
nlmsg_free(skb);
return -ENOMEM;
}
/* fill the data */
attr = nla_reserve(skb, REG_GENL_ATTR_EVENT, sizeof(struct reg_genl_event));
if (!attr) {
nlmsg_free(skb);
return -EINVAL;
}
edata = nla_data(attr);
memset(edata, 0, sizeof(struct reg_genl_event));
strscpy(edata->reg_name, reg_name, sizeof(edata->reg_name));
edata->event = event;
/* send multicast genetlink message */
genlmsg_end(skb, msg_header);
size = genlmsg_multicast(&reg_event_genl_family, skb, 0, 0, GFP_ATOMIC);
return size;
}
static int __init reg_event_genetlink_init(void)
{
return genl_register_family(&reg_event_genl_family);
}
static int __init reg_event_init(void)
{
int error;
/* create genetlink for acpi event */
error = reg_event_genetlink_init();
if (error)
pr_warn("Failed to create genetlink family for reg event\n");
return 0;
}
fs_initcall(reg_event_init);
......@@ -131,6 +131,8 @@ static int of_get_regulation_constraints(struct device *dev,
constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS;
constraints->pull_down = of_property_read_bool(np, "regulator-pull-down");
constraints->system_critical = of_property_read_bool(np,
"system-critical-regulator");
if (of_property_read_bool(np, "regulator-allow-bypass"))
constraints->valid_ops_mask |= REGULATOR_CHANGE_BYPASS;
......@@ -173,6 +175,13 @@ static int of_get_regulation_constraints(struct device *dev,
if (!ret)
constraints->enable_time = pval;
ret = of_property_read_u32(np, "regulator-uv-survival-time-ms", &pval);
if (!ret)
constraints->uv_less_critical_window_ms = pval;
else
constraints->uv_less_critical_window_ms =
REGULATOR_DEF_UV_LESS_CRITICAL_WINDOW_MS;
constraints->soft_start = of_property_read_bool(np,
"regulator-soft-start");
ret = of_property_read_u32(np, "regulator-active-discharge", &pval);
......
......@@ -1594,7 +1594,7 @@ static const struct of_device_id of_palmas_match_tbl[] = {
static int palmas_regulators_probe(struct platform_device *pdev)
{
struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
struct palmas_pmic_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct palmas_pmic_platform_data *pdata;
struct device_node *node = pdev->dev.of_node;
struct palmas_pmic_driver_data *driver_data;
struct regulator_config config = { };
......
This diff is collapsed.
......@@ -796,6 +796,7 @@ static const struct rpm_regulator_data rpm_mp5496_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &mp5496_smps, "s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &mp5496_smps, "s2" },
{ "l2", QCOM_SMD_RPM_LDOA, 2, &mp5496_ldoa2, "l2" },
{ "l5", QCOM_SMD_RPM_LDOA, 5, &mp5496_ldoa2, "l5" },
{}
};
......@@ -1012,6 +1013,39 @@ static const struct rpm_regulator_data rpm_pm8916_regulators[] = {
{}
};
static const struct rpm_regulator_data rpm_pm8937_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8994_hfsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8994_hfsmps, "vdd_s2" },
{ "s3", QCOM_SMD_RPM_SMPA, 3, &pm8994_hfsmps, "vdd_s3" },
{ "s4", QCOM_SMD_RPM_SMPA, 4, &pm8994_hfsmps, "vdd_s4" },
/* S5 - S6 are managed by SPMI */
{ "l1", QCOM_SMD_RPM_LDOA, 1, &pm8953_ult_nldo, "vdd_l1_l19" },
{ "l2", QCOM_SMD_RPM_LDOA, 2, &pm8953_ult_nldo, "vdd_l2_l23" },
{ "l3", QCOM_SMD_RPM_LDOA, 3, &pm8953_ult_nldo, "vdd_l3" },
{ "l4", QCOM_SMD_RPM_LDOA, 4, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" },
{ "l5", QCOM_SMD_RPM_LDOA, 5, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" },
{ "l6", QCOM_SMD_RPM_LDOA, 6, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" },
{ "l7", QCOM_SMD_RPM_LDOA, 7, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" },
{ "l8", QCOM_SMD_RPM_LDOA, 8, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" },
{ "l9", QCOM_SMD_RPM_LDOA, 9, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" },
{ "l10", QCOM_SMD_RPM_LDOA, 10, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18"},
{ "l11", QCOM_SMD_RPM_LDOA, 11, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" },
{ "l12", QCOM_SMD_RPM_LDOA, 12, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" },
{ "l13", QCOM_SMD_RPM_LDOA, 13, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" },
{ "l14", QCOM_SMD_RPM_LDOA, 14, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" },
{ "l15", QCOM_SMD_RPM_LDOA, 15, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" },
{ "l16", QCOM_SMD_RPM_LDOA, 16, &pm8950_ult_pldo, "vdd_l4_l5_l6_l7_l16" },
{ "l17", QCOM_SMD_RPM_LDOA, 17, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" },
{ "l18", QCOM_SMD_RPM_LDOA, 18, &pm8950_ult_pldo, "vdd_l9_l10_l13_l14_l15_l18" },
{ "l19", QCOM_SMD_RPM_LDOA, 19, &pm8953_ult_nldo, "vdd_l1_l19" },
{ "l20", QCOM_SMD_RPM_LDOA, 20, &pm8953_lnldo, "vdd_l20_l21" },
{ "l21", QCOM_SMD_RPM_LDOA, 21, &pm8953_lnldo, "vdd_l20_l21" },
{ "l22", QCOM_SMD_RPM_LDOA, 22, &pm8950_ult_pldo, "vdd_l8_l11_l12_l17_l22" },
{ "l23", QCOM_SMD_RPM_LDOA, 23, &pm8994_nldo, "vdd_l2_l23" },
{}
};
static const struct rpm_regulator_data rpm_pm8941_regulators[] = {
{ "s1", QCOM_SMD_RPM_SMPA, 1, &pm8x41_hfsmps, "vdd_s1" },
{ "s2", QCOM_SMD_RPM_SMPA, 2, &pm8x41_hfsmps, "vdd_s2" },
......@@ -1329,6 +1363,7 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators },
{ .compatible = "qcom,rpm-pm8909-regulators", .data = &rpm_pm8909_regulators },
{ .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators },
{ .compatible = "qcom,rpm-pm8937-regulators", .data = &rpm_pm8937_regulators },
{ .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators },
{ .compatible = "qcom,rpm-pm8950-regulators", .data = &rpm_pm8950_regulators },
{ .compatible = "qcom,rpm-pm8953-regulators", .data = &rpm_pm8953_regulators },
......
......@@ -2239,6 +2239,39 @@ static const struct spmi_regulator_data pm8916_regulators[] = {
{ }
};
static const struct spmi_regulator_data pm8937_regulators[] = {
{ "s1", 0x1400, "vdd_s1", },
{ "s2", 0x1700, "vdd_s2", },
{ "s3", 0x1a00, "vdd_s3", },
{ "s4", 0x1d00, "vdd_s4", },
{ "s5", 0x2000, "vdd_s5", },
{ "s6", 0x2300, "vdd_s6", },
{ "l1", 0x4000, "vdd_l1_l19", },
{ "l2", 0x4100, "vdd_l2_l23", },
{ "l3", 0x4200, "vdd_l3", },
{ "l4", 0x4300, "vdd_l4_l5_l6_l7_l16", },
{ "l5", 0x4400, "vdd_l4_l5_l6_l7_l16", },
{ "l6", 0x4500, "vdd_l4_l5_l6_l7_l16", },
{ "l7", 0x4600, "vdd_l4_l5_l6_l7_l16", },
{ "l8", 0x4700, "vdd_l8_l11_l12_l17_l22", },
{ "l9", 0x4800, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l10", 0x4900, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l11", 0x4a00, "vdd_l8_l11_l12_l17_l22", },
{ "l12", 0x4b00, "vdd_l8_l11_l12_l17_l22", },
{ "l13", 0x4c00, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l14", 0x4d00, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l15", 0x4e00, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l16", 0x4f00, "vdd_l4_l5_l6_l7_l16", },
{ "l17", 0x5000, "vdd_l8_l11_l12_l17_l22", },
{ "l18", 0x5100, "vdd_l9_l10_l13_l14_l15_l18", },
{ "l19", 0x5200, "vdd_l1_l19", },
{ "l20", 0x5300, "vdd_l20_l21", },
{ "l21", 0x5400, "vdd_l21_l21", },
{ "l22", 0x5500, "vdd_l8_l11_l12_l17_l22", },
{ "l23", 0x5600, "vdd_l2_l23", },
{ }
};
static const struct spmi_regulator_data pm8941_regulators[] = {
{ "s1", 0x1400, "vdd_s1", },
{ "s2", 0x1700, "vdd_s2", },
......@@ -2453,6 +2486,7 @@ static const struct of_device_id qcom_spmi_regulator_match[] = {
{ .compatible = "qcom,pm8841-regulators", .data = &pm8841_regulators },
{ .compatible = "qcom,pm8909-regulators", .data = &pm8909_regulators },
{ .compatible = "qcom,pm8916-regulators", .data = &pm8916_regulators },
{ .compatible = "qcom,pm8937-regulators", .data = &pm8937_regulators },
{ .compatible = "qcom,pm8941-regulators", .data = &pm8941_regulators },
{ .compatible = "qcom,pm8950-regulators", .data = &pm8950_regulators },
{ .compatible = "qcom,pm8994-regulators", .data = &pm8994_regulators },
......
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Regulator event over netlink
*
* Author: Naresh Solanki <Naresh.Solanki@9elements.com>
*/
#ifndef __REGULATOR_EVENT_H
#define __REGULATOR_EVENT_H
int reg_generate_netlink_event(const char *reg_name, u64 event);
#endif
......@@ -233,7 +233,7 @@ static int stm32_vrefbuf_probe(struct platform_device *pdev)
return ret;
}
static int stm32_vrefbuf_remove(struct platform_device *pdev)
static void stm32_vrefbuf_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
struct stm32_vrefbuf *priv = rdev_get_drvdata(rdev);
......@@ -244,8 +244,6 @@ static int stm32_vrefbuf_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
return 0;
};
static int __maybe_unused stm32_vrefbuf_runtime_suspend(struct device *dev)
......@@ -282,7 +280,7 @@ MODULE_DEVICE_TABLE(of, stm32_vrefbuf_of_match);
static struct platform_driver stm32_vrefbuf_driver = {
.probe = stm32_vrefbuf_probe,
.remove = stm32_vrefbuf_remove,
.remove_new = stm32_vrefbuf_remove,
.driver = {
.name = "stm32-vrefbuf",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
......@@ -15,7 +15,7 @@
#include <dt-bindings/mfd/st,stpmic1.h>
/**
* struct stpmic1 regulator description: this structure is used as driver data
* struct stpmic1_regulator_cfg - this structure is used as driver data
* @desc: regulator framework description
* @mask_reset_reg: mask reset register address
* @mask_reset_mask: mask rank and mask reset register mask
......
......@@ -115,7 +115,7 @@ static int uniphier_regulator_probe(struct platform_device *pdev)
return ret;
}
static int uniphier_regulator_remove(struct platform_device *pdev)
static void uniphier_regulator_remove(struct platform_device *pdev)
{
struct uniphier_regulator_priv *priv = platform_get_drvdata(pdev);
int i;
......@@ -124,8 +124,6 @@ static int uniphier_regulator_remove(struct platform_device *pdev)
reset_control_assert(priv->rst[i]);
clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
return 0;
}
/* USB3 controller data */
......@@ -209,7 +207,7 @@ MODULE_DEVICE_TABLE(of, uniphier_regulator_match);
static struct platform_driver uniphier_regulator_driver = {
.probe = uniphier_regulator_probe,
.remove = uniphier_regulator_remove,
.remove_new = uniphier_regulator_remove,
.driver = {
.name = "uniphier-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
......@@ -194,7 +194,7 @@ static int regulator_userspace_consumer_probe(struct platform_device *pdev)
return ret;
}
static int regulator_userspace_consumer_remove(struct platform_device *pdev)
static void regulator_userspace_consumer_remove(struct platform_device *pdev)
{
struct userspace_consumer_data *data = platform_get_drvdata(pdev);
......@@ -202,8 +202,6 @@ static int regulator_userspace_consumer_remove(struct platform_device *pdev)
if (data->enabled && !data->no_autoswitch)
regulator_bulk_disable(data->num_supplies, data->supplies);
return 0;
}
static const struct of_device_id regulator_userspace_consumer_of_match[] = {
......@@ -213,7 +211,7 @@ static const struct of_device_id regulator_userspace_consumer_of_match[] = {
static struct platform_driver regulator_userspace_consumer_driver = {
.probe = regulator_userspace_consumer_probe,
.remove = regulator_userspace_consumer_remove,
.remove_new = regulator_userspace_consumer_remove,
.driver = {
.name = "reg-userspace-consumer",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
......@@ -345,7 +345,7 @@ static int regulator_virtual_probe(struct platform_device *pdev)
return 0;
}
static int regulator_virtual_remove(struct platform_device *pdev)
static void regulator_virtual_remove(struct platform_device *pdev)
{
struct virtual_consumer_data *drvdata = platform_get_drvdata(pdev);
......@@ -353,13 +353,11 @@ static int regulator_virtual_remove(struct platform_device *pdev)
if (drvdata->enabled)
regulator_disable(drvdata->regulator);
return 0;
}
static struct platform_driver regulator_virtual_consumer_driver = {
.probe = regulator_virtual_probe,
.remove = regulator_virtual_remove,
.remove_new = regulator_virtual_remove,
.driver = {
.name = "reg-virt-consumer",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
......@@ -1158,14 +1158,12 @@ static int wm8350_regulator_probe(struct platform_device *pdev)
return 0;
}
static int wm8350_regulator_remove(struct platform_device *pdev)
static void wm8350_regulator_remove(struct platform_device *pdev)
{
struct regulator_dev *rdev = platform_get_drvdata(pdev);
struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq, rdev);
return 0;
}
int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
......@@ -1306,7 +1304,7 @@ EXPORT_SYMBOL_GPL(wm8350_register_led);
static struct platform_driver wm8350_regulator_driver = {
.probe = wm8350_regulator_probe,
.remove = wm8350_regulator_remove,
.remove_new = wm8350_regulator_remove,
.driver = {
.name = "wm8350-regulator",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
......
......@@ -33,6 +33,7 @@
#include <linux/err.h>
#include <linux/suspend.h>
#include <regulator/regulator.h>
struct device;
struct notifier_block;
......@@ -84,52 +85,6 @@ struct regulator_dev;
#define REGULATOR_MODE_IDLE 0x4
#define REGULATOR_MODE_STANDBY 0x8
/*
* Regulator notifier events.
*
* UNDER_VOLTAGE Regulator output is under voltage.
* OVER_CURRENT Regulator output current is too high.
* REGULATION_OUT Regulator output is out of regulation.
* FAIL Regulator output has failed.
* OVER_TEMP Regulator over temp.
* FORCE_DISABLE Regulator forcibly shut down by software.
* VOLTAGE_CHANGE Regulator voltage changed.
* Data passed is old voltage cast to (void *).
* DISABLE Regulator was disabled.
* PRE_VOLTAGE_CHANGE Regulator is about to have voltage changed.
* Data passed is "struct pre_voltage_change_data"
* ABORT_VOLTAGE_CHANGE Regulator voltage change failed for some reason.
* Data passed is old voltage cast to (void *).
* PRE_DISABLE Regulator is about to be disabled
* ABORT_DISABLE Regulator disable failed for some reason
*
* NOTE: These events can be OR'ed together when passed into handler.
*/
#define REGULATOR_EVENT_UNDER_VOLTAGE 0x01
#define REGULATOR_EVENT_OVER_CURRENT 0x02
#define REGULATOR_EVENT_REGULATION_OUT 0x04
#define REGULATOR_EVENT_FAIL 0x08
#define REGULATOR_EVENT_OVER_TEMP 0x10
#define REGULATOR_EVENT_FORCE_DISABLE 0x20
#define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40
#define REGULATOR_EVENT_DISABLE 0x80
#define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100
#define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200
#define REGULATOR_EVENT_PRE_DISABLE 0x400
#define REGULATOR_EVENT_ABORT_DISABLE 0x800
#define REGULATOR_EVENT_ENABLE 0x1000
/*
* Following notifications should be emitted only if detected condition
* is such that the HW is likely to still be working but consumers should
* take a recovery action to prevent problems esacalating into errors.
*/
#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
#define REGULATOR_EVENT_OVER_CURRENT_WARN 0x4000
#define REGULATOR_EVENT_OVER_VOLTAGE_WARN 0x8000
#define REGULATOR_EVENT_OVER_TEMP_WARN 0x10000
#define REGULATOR_EVENT_WARN_MASK 0x1E000
/*
* Regulator errors that can be queried using regulator_get_error_flags
*
......
......@@ -51,12 +51,7 @@ enum regulator_detection_severity {
/* Initialize struct linear_range for regulators */
#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \
{ \
.min = _min_uV, \
.min_sel = _min_sel, \
.max_sel = _max_sel, \
.step = _step_uV, \
}
LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV)
/**
* struct regulator_ops - regulator operations.
......
......@@ -49,6 +49,13 @@ struct regulator;
#define DISABLE_IN_SUSPEND 1
#define ENABLE_IN_SUSPEND 2
/*
* Default time window (in milliseconds) following a critical under-voltage
* event during which less critical actions can be safely carried out by the
* system.
*/
#define REGULATOR_DEF_UV_LESS_CRITICAL_WINDOW_MS 10
/* Regulator active discharge flags */
enum regulator_active_discharge {
REGULATOR_ACTIVE_DISCHARGE_DEFAULT,
......@@ -127,6 +134,8 @@ struct notification_limit {
* @ramp_disable: Disable ramp delay when initialising or when setting voltage.
* @soft_start: Enable soft start so that voltage ramps slowly.
* @pull_down: Enable pull down when regulator is disabled.
* @system_critical: Set if the regulator is critical to system stability or
* functionality.
* @over_current_protection: Auto disable on over current event.
*
* @over_current_detection: Configure over current limits.
......@@ -153,6 +162,13 @@ struct notification_limit {
* regulator_active_discharge values are used for
* initialisation.
* @enable_time: Turn-on time of the rails (unit: microseconds)
* @uv_less_critical_window_ms: Specifies the time window (in milliseconds)
* following a critical under-voltage (UV) event
* during which less critical actions can be
* safely carried out by the system (for example
* logging). After this time window more critical
* actions should be done (for example prevent
* HW damage).
*/
struct regulation_constraints {
......@@ -204,6 +220,7 @@ struct regulation_constraints {
unsigned int settling_time_up;
unsigned int settling_time_down;
unsigned int enable_time;
unsigned int uv_less_critical_window_ms;
unsigned int active_discharge;
......@@ -214,6 +231,7 @@ struct regulation_constraints {
unsigned ramp_disable:1; /* disable ramp delay */
unsigned soft_start:1; /* ramp voltage slowly */
unsigned pull_down:1; /* pull down resistor when regulator off */
unsigned system_critical:1; /* critical to system stability */
unsigned over_current_protection:1; /* auto disable on over current */
unsigned over_current_detection:1; /* notify on over current */
unsigned over_voltage_detection:1; /* notify on over voltage */
......
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Regulator uapi header
*
* Author: Naresh Solanki <Naresh.Solanki@9elements.com>
*/
#ifndef _UAPI_REGULATOR_H
#define _UAPI_REGULATOR_H
#ifdef __KERNEL__
#include <linux/types.h>
#else
#include <stdint.h>
#endif
/*
* Regulator notifier events.
*
* UNDER_VOLTAGE Regulator output is under voltage.
* OVER_CURRENT Regulator output current is too high.
* REGULATION_OUT Regulator output is out of regulation.
* FAIL Regulator output has failed.
* OVER_TEMP Regulator over temp.
* FORCE_DISABLE Regulator forcibly shut down by software.
* VOLTAGE_CHANGE Regulator voltage changed.
* Data passed is old voltage cast to (void *).
* DISABLE Regulator was disabled.
* PRE_VOLTAGE_CHANGE Regulator is about to have voltage changed.
* Data passed is "struct pre_voltage_change_data"
* ABORT_VOLTAGE_CHANGE Regulator voltage change failed for some reason.
* Data passed is old voltage cast to (void *).
* PRE_DISABLE Regulator is about to be disabled
* ABORT_DISABLE Regulator disable failed for some reason
*
* NOTE: These events can be OR'ed together when passed into handler.
*/
#define REGULATOR_EVENT_UNDER_VOLTAGE 0x01
#define REGULATOR_EVENT_OVER_CURRENT 0x02
#define REGULATOR_EVENT_REGULATION_OUT 0x04
#define REGULATOR_EVENT_FAIL 0x08
#define REGULATOR_EVENT_OVER_TEMP 0x10
#define REGULATOR_EVENT_FORCE_DISABLE 0x20
#define REGULATOR_EVENT_VOLTAGE_CHANGE 0x40
#define REGULATOR_EVENT_DISABLE 0x80
#define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100
#define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200
#define REGULATOR_EVENT_PRE_DISABLE 0x400
#define REGULATOR_EVENT_ABORT_DISABLE 0x800
#define REGULATOR_EVENT_ENABLE 0x1000
/*
* Following notifications should be emitted only if detected condition
* is such that the HW is likely to still be working but consumers should
* take a recovery action to prevent problems escalating into errors.
*/
#define REGULATOR_EVENT_UNDER_VOLTAGE_WARN 0x2000
#define REGULATOR_EVENT_OVER_CURRENT_WARN 0x4000
#define REGULATOR_EVENT_OVER_VOLTAGE_WARN 0x8000
#define REGULATOR_EVENT_OVER_TEMP_WARN 0x10000
#define REGULATOR_EVENT_WARN_MASK 0x1E000
struct reg_genl_event {
char reg_name[32];
uint64_t event;
};
/* attributes of reg_genl_family */
enum {
REG_GENL_ATTR_UNSPEC,
REG_GENL_ATTR_EVENT, /* reg event info needed by user space */
__REG_GENL_ATTR_MAX,
};
#define REG_GENL_ATTR_MAX (__REG_GENL_ATTR_MAX - 1)
/* commands supported by the reg_genl_family */
enum {
REG_GENL_CMD_UNSPEC,
REG_GENL_CMD_EVENT, /* kernel->user notifications for reg events */
__REG_GENL_CMD_MAX,
};
#define REG_GENL_CMD_MAX (__REG_GENL_CMD_MAX - 1)
#define REG_GENL_FAMILY_NAME "reg_event"
#define REG_GENL_VERSION 0x01
#define REG_GENL_MCAST_GROUP_NAME "reg_mc_group"
#endif /* _UAPI_REGULATOR_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment