diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-10 01:41:21 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-10 01:41:21 +0300 |
commit | da96801729b43eb6229425a23b7bdf6045685251 (patch) | |
tree | 4cec3b1531cc7ea77eaf14726d915d1318805a4c | |
parent | 83130ff423d61b018e1018cfa9ca5c1511b5f33b (diff) | |
parent | 1cadc04c1a1ac5015c2eb0fadfabf4b61bbe167e (diff) | |
download | linux-da96801729b43eb6229425a23b7bdf6045685251.tar.xz |
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
...
30 files changed, 638 insertions, 141 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 8a01b8112f0b..e0891ac76ab3 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -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. diff --git a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml index ce7751b9129c..9ff9abf2691a 100644 --- a/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/fixed-regulator.yaml @@ -105,6 +105,8 @@ properties: description: Interrupt signaling a critical under-voltage event. + system-critical-regulator: true + required: - compatible - regulator-name diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml index acd37f28ef53..27c6d5152413 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml @@ -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 @@ -242,6 +244,18 @@ allOf: 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: + enum: - qcom,pm8150-rpmh-regulators - qcom,pmc8180-rpmh-regulators - qcom,pmm8155au-rpmh-regulators diff --git a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml index 9ea8ac0786ac..f2fd2df68a9e 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,smd-rpm-regulator.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml index 7a1b7d2abbd4..aea849e8eadf 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,spmi-regulator.yaml @@ -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 @@ -296,6 +297,24 @@ allOf: 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: + contains: + enum: - qcom,pm8950-regulators then: properties: diff --git a/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml index 89c564dfa5db..534f87e98716 100644 --- a/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/qcom,usb-vbus-regulator.yaml @@ -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>; diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml index 9daf0fc2465f..1ef380d1515e 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.yaml +++ b/Documentation/devicetree/bindings/regulator/regulator.yaml @@ -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 diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f3ec24691378..550145f82726 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -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 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index b2b059b5ee56..46fb569e6be8 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -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 diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index b465c0010665..4b54068d4f59 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -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, diff --git a/drivers/regulator/bd9571mwv-regulator.c b/drivers/regulator/bd9571mwv-regulator.c index d469481d8442..c7ceba56e7dc 100644 --- a/drivers/regulator/bd9571mwv-regulator.c +++ b/drivers/regulator/bd9571mwv-regulator.c @@ -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); diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 3137e40fcd3e..a968dabb48f5 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -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,7 +2920,8 @@ static int _regulator_enable(struct regulator *regulator) /* Fallthrough on positive return values - already enabled */ } - rdev->use_count++; + if (regulator->enable_count == 1) + rdev->use_count++; return 0; @@ -2993,37 +2996,40 @@ 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; - /* are we the last user and permitted to disable ? */ - if (rdev->use_count == 1 && - (rdev->constraints && !rdev->constraints->always_on)) { - - /* we are last user */ - if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { - ret = _notifier_call_chain(rdev, - REGULATOR_EVENT_PRE_DISABLE, - NULL); - if (ret & NOTIFY_STOP_MASK) - return -EINVAL; - - ret = _regulator_do_disable(rdev); - if (ret < 0) { - rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret)); - _notifier_call_chain(rdev, - REGULATOR_EVENT_ABORT_DISABLE, + 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)) { + + /* we are last user */ + if (regulator_ops_is_valid(rdev, REGULATOR_CHANGE_STATUS)) { + ret = _notifier_call_chain(rdev, + REGULATOR_EVENT_PRE_DISABLE, + NULL); + if (ret & NOTIFY_STOP_MASK) + return -EINVAL; + + ret = _regulator_do_disable(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to disable: %pe\n", ERR_PTR(ret)); + _notifier_call_chain(rdev, + REGULATOR_EVENT_ABORT_DISABLE, + NULL); + return ret; + } + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, NULL); - return ret; } - _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, - NULL); - } - rdev->use_count = 0; - } else if (rdev->use_count > 1) { - rdev->use_count--; + rdev->use_count = 0; + } else if (rdev->use_count > 1) { + rdev->use_count--; + } } if (ret == 0) @@ -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, @@ -5062,6 +5084,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 * @event: notifier block @@ -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 @@ unlock: 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(®ulator_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 diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c index 34c5e485d0af..1e2d54da1b9a 100644 --- a/drivers/regulator/db8500-prcmu.c +++ b/drivers/regulator/db8500-prcmu.c @@ -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) diff --git a/drivers/regulator/event.c b/drivers/regulator/event.c new file mode 100644 index 000000000000..ea3bd49544e8 --- /dev/null +++ b/drivers/regulator/event.c @@ -0,0 +1,91 @@ +// 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(®_event_seqnum), + ®_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(®_event_genl_family, skb, 0, 0, GFP_ATOMIC); + + return size; +} + +static int __init reg_event_genetlink_init(void) +{ + return genl_register_family(®_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); diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 1b65e5e4e40f..03afc160fc72 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -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); diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index e0dc033aae0f..60656a815b9e 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -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 = { }; diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index cf502eec0915..80e304711345 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. +// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. #define pr_fmt(fmt) "%s: " fmt, __func__ @@ -68,10 +69,11 @@ enum rpmh_regulator_type { * @regulator_type: RPMh accelerator type used to manage this * regulator * @ops: Pointer to regulator ops callback structure - * @voltage_range: The single range of voltages supported by this - * PMIC regulator type + * @voltage_ranges: The possible ranges of voltages supported by this + * PMIC regulator type + * @n_linear_ranges: Number of entries in voltage_ranges * @n_voltages: The number of unique voltage set points defined - * by voltage_range + * by voltage_ranges * @hpm_min_load_uA: Minimum load current in microamps that requires * high power mode (HPM) operation. This is used * for LDO hardware type regulators only. @@ -85,7 +87,8 @@ enum rpmh_regulator_type { struct rpmh_vreg_hw_data { enum rpmh_regulator_type regulator_type; const struct regulator_ops *ops; - const struct linear_range voltage_range; + const struct linear_range *voltage_ranges; + int n_linear_ranges; int n_voltages; int hpm_min_load_uA; const int *pmic_mode_map; @@ -449,8 +452,8 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev, vreg->mode = REGULATOR_MODE_INVALID; if (rpmh_data->hw_data->n_voltages) { - vreg->rdesc.linear_ranges = &rpmh_data->hw_data->voltage_range; - vreg->rdesc.n_linear_ranges = 1; + vreg->rdesc.linear_ranges = rpmh_data->hw_data->voltage_ranges; + vreg->rdesc.n_linear_ranges = rpmh_data->hw_data->n_linear_ranges; vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages; } @@ -508,6 +511,14 @@ static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_FAST] = -EINVAL, }; +static const int pmic_mode_map_pmic5_ldo_hpm[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = -EINVAL, + [REGULATOR_MODE_IDLE] = -EINVAL, + [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM, + [REGULATOR_MODE_FAST] = -EINVAL, +}; + static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) { unsigned int mode; @@ -613,7 +624,10 @@ static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) static const struct rpmh_vreg_hw_data pmic4_pldo = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 256, .hpm_min_load_uA = 10000, .pmic_mode_map = pmic_mode_map_pmic4_ldo, @@ -623,7 +637,10 @@ static const struct rpmh_vreg_hw_data pmic4_pldo = { static const struct rpmh_vreg_hw_data pmic4_pldo_lv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 128, .hpm_min_load_uA = 10000, .pmic_mode_map = pmic_mode_map_pmic4_ldo, @@ -633,7 +650,10 @@ static const struct rpmh_vreg_hw_data pmic4_pldo_lv = { static const struct rpmh_vreg_hw_data pmic4_nldo = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 128, .hpm_min_load_uA = 30000, .pmic_mode_map = pmic_mode_map_pmic4_ldo, @@ -643,7 +663,10 @@ static const struct rpmh_vreg_hw_data pmic4_nldo = { static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 216, .pmic_mode_map = pmic_mode_map_pmic4_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -652,7 +675,10 @@ static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = { static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000), + }, + .n_linear_ranges = 1, .n_voltages = 259, .pmic_mode_map = pmic_mode_map_pmic4_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -661,7 +687,10 @@ static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = { static const struct rpmh_vreg_hw_data pmic4_bob = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_bypass_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000), + }, + .n_linear_ranges = 1, .n_voltages = 84, .pmic_mode_map = pmic_mode_map_pmic4_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, @@ -676,7 +705,10 @@ static const struct rpmh_vreg_hw_data pmic4_lvs = { static const struct rpmh_vreg_hw_data pmic5_pldo = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 256, .hpm_min_load_uA = 10000, .pmic_mode_map = pmic_mode_map_pmic5_ldo, @@ -686,7 +718,10 @@ static const struct rpmh_vreg_hw_data pmic5_pldo = { static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 63, .hpm_min_load_uA = 10000, .pmic_mode_map = pmic_mode_map_pmic5_ldo, @@ -696,17 +731,50 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 188, .hpm_min_load_uA = 10000, .pmic_mode_map = pmic_mode_map_pmic5_ldo, .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_pldo502 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 256, + .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo502ln = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(1800000, 0, 2, 200000), + REGULATOR_LINEAR_RANGE(2608000, 3, 28, 16000), + REGULATOR_LINEAR_RANGE(3104000, 29, 30, 96000), + REGULATOR_LINEAR_RANGE(3312000, 31, 31, 0), + }, + .n_linear_ranges = 4, + .n_voltages = 32, + .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + static const struct rpmh_vreg_hw_data pmic5_nldo = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 124, .hpm_min_load_uA = 30000, .pmic_mode_map = pmic_mode_map_pmic5_ldo, @@ -716,17 +784,36 @@ static const struct rpmh_vreg_hw_data pmic5_nldo = { static const struct rpmh_vreg_hw_data pmic5_nldo515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_drms_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 211, .hpm_min_load_uA = 30000, .pmic_mode_map = pmic_mode_map_pmic5_ldo, .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, }; +static const struct rpmh_vreg_hw_data pmic5_nldo502 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(528000, 0, 127, 8000), + }, + .n_linear_ranges = 1, + .n_voltages = 128, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 216, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -735,7 +822,10 @@ static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = { static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + }, + .n_linear_ranges = 1, .n_voltages = 264, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -744,7 +834,10 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + }, + .n_linear_ranges = 1, .n_voltages = 264, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -753,7 +846,10 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = { static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000), + }, + .n_linear_ranges = 1, .n_voltages = 268, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -762,7 +858,10 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = { static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 268, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -771,7 +870,10 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = { static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + }, + .n_linear_ranges = 1, .n_voltages = 215, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -780,7 +882,10 @@ static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = { static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000), + }, + .n_linear_ranges = 1, .n_voltages = 236, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -789,7 +894,10 @@ static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { static const struct rpmh_vreg_hw_data pmic5_hfsmps515_1 = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(900000, 0, 4, 16000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(900000, 0, 4, 16000), + }, + .n_linear_ranges = 1, .n_voltages = 5, .pmic_mode_map = pmic_mode_map_pmic5_smps, .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, @@ -798,7 +906,10 @@ static const struct rpmh_vreg_hw_data pmic5_hfsmps515_1 = { static const struct rpmh_vreg_hw_data pmic5_bob = { .regulator_type = VRM, .ops = &rpmh_regulator_vrm_bypass_ops, - .voltage_range = REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000), + .voltage_ranges = (struct linear_range[]) { + REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000), + }, + .n_linear_ranges = 1, .n_voltages = 32, .pmic_mode_map = pmic_mode_map_pmic5_bob, .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, @@ -1147,6 +1258,16 @@ static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = { {} }; +static const struct rpmh_vreg_init_data pm8010_vreg_data[] = { + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo502, "vdd-l1-l2"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo502, "vdd-l1-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo502ln, "vdd-l3-l4"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo502ln, "vdd-l3-l4"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo502, "vdd-l5"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo502ln, "vdd-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo502, "vdd-l7"), +}; + static const struct rpmh_vreg_init_data pm6150_vreg_data[] = { RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), @@ -1463,6 +1584,10 @@ static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = { .data = pm8009_1_vreg_data, }, { + .compatible = "qcom,pm8010-rpmh-regulators", + .data = pm8010_vreg_data, + }, + { .compatible = "qcom,pm8150-rpmh-regulators", .data = pm8150_vreg_data, }, diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index f53ada076252..d1be9568025e 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -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 }, diff --git a/drivers/regulator/qcom_spmi-regulator.c b/drivers/regulator/qcom_spmi-regulator.c index 94f9092b29ef..9a9fa20dcd95 100644 --- a/drivers/regulator/qcom_spmi-regulator.c +++ b/drivers/regulator/qcom_spmi-regulator.c @@ -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 }, diff --git a/drivers/regulator/regnl.h b/drivers/regulator/regnl.h new file mode 100644 index 000000000000..bcba16cc05cc --- /dev/null +++ b/drivers/regulator/regnl.h @@ -0,0 +1,13 @@ +/* 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 diff --git a/drivers/regulator/stm32-vrefbuf.c b/drivers/regulator/stm32-vrefbuf.c index 717144cbe0f9..40855105dd33 100644 --- a/drivers/regulator/stm32-vrefbuf.c +++ b/drivers/regulator/stm32-vrefbuf.c @@ -233,7 +233,7 @@ err_pm_stop: 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, diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c index 79d1a3eb18d4..a498df7cb016 100644 --- a/drivers/regulator/stpmic1_regulator.c +++ b/drivers/regulator/stpmic1_regulator.c @@ -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 diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index 1d8304b88bd6..5f868042392f 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -115,7 +115,7 @@ out_rst_assert: 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, diff --git a/drivers/regulator/userspace-consumer.c b/drivers/regulator/userspace-consumer.c index 97f075ed68c9..53d1b9d6f69c 100644 --- a/drivers/regulator/userspace-consumer.c +++ b/drivers/regulator/userspace-consumer.c @@ -194,7 +194,7 @@ err_enable: 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, diff --git a/drivers/regulator/virtual.c b/drivers/regulator/virtual.c index d5a160efdae6..0a0ee186c6af 100644 --- a/drivers/regulator/virtual.c +++ b/drivers/regulator/virtual.c @@ -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, diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index 1445bafcab40..9939a5d2cbec 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -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, diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h index 39b666b40ea6..4660582a3302 100644 --- a/include/linux/regulator/consumer.h +++ b/include/linux/regulator/consumer.h @@ -33,6 +33,7 @@ #include <linux/err.h> #include <linux/suspend.h> +#include <regulator/regulator.h> struct device; struct notifier_block; @@ -85,52 +86,6 @@ struct regulator_dev; #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 * * UNDER_VOLTAGE Regulator output is under voltage. diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4b7eceb3828b..22a07c0900a4 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -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. diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index 621b7f4a3639..0cd76d264727 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -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 */ diff --git a/include/uapi/regulator/regulator.h b/include/uapi/regulator/regulator.h new file mode 100644 index 000000000000..71bf71a22e7f --- /dev/null +++ b/include/uapi/regulator/regulator.h @@ -0,0 +1,90 @@ +/* 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 */ |