Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge series "regulator_sync_state() support" from Saravana Kannan <saravanak@google.com>:

Consider the following example:
- regulator-X is provided by device-X.
- regulator-X is a supplier to device-A, device-B and device-C.
- device-A is off/inactive from boot.
- device-B and device-C are left on/active by the bootloader
- regulator-X is left on boot by the bootloader at 2000 mV to supply
device-B and device-C.

Example boot sequence 1:
1. device-X is probed successfully.
2. device-A is probed by driver-A
a. driver-A gets regulator-X
b. driver-A votes on regulator-X
c. driver-A initializes device-A
d. driver-A votes off regulator-X
e. regulator-X is turned off.
3. System crashes or device-B and device-C become unreliable because
regulator-X was turned off without following the proper quiescing
steps for device-B and device-C.

Example boot sequence 2:
1. device-X is probed successfully.
2. device-B is probed by driver-B
a. driver-B gets regulator-X
b. driver-B votes on regulator-X
c. driver-B lowers device-B performance point.
d. driver-B lowers voltage vote to 1000 mV.
e. regulator-X voltage is lowered to 1000 mV.
3. System crashes or device-C becomes unreliable because regulator-X
voltage was lowered to 1000 mV when device-C still needed it at 2000 mV

This patch series makes sure these examples are handled correctly and
system crash or device instability is avoided and the system remains
usable.

More details provided in the commit texts.

v2->v3:
Patch 2/4 - No functional change. Simple refactor.
Patch 3/4
- Was Patch 2/2 in v2.
- Rewrote commit text to hopefully address all previous points.
- Renamed variable/functions. Hope it's clearer.
- Added more comments.
- Added logging
- Fixed timeout functionality.
- Handle exclusive consumers properly
- Handle coupled regulators properly
Patch 4/4 - Prevents voltage from going too low during boot.

v1->v2:
Patch 1/2
- New patch
Patch 2/2
- This was the only patch in v1
- Made the late_initcall_sync timeout a commandline param
- If timeout is set, we also give up waiting for all consumers after
the timeout expires.
- Made every regulator driver add sync_state() support

Saravana Kannan (4):
driver core: Add dev_set_drv_sync_state()
regulator: core: Add destroy_regulator()
regulator: core: Add basic enable/disable support for sync_state()
callbacks
regulator: core: Add voltage support for sync_state() callbacks

drivers/regulator/core.c | 200 ++++++++++++++++++++++++++++---
include/linux/device.h | 12 ++
include/linux/regulator/driver.h | 2 +
3 files changed, 198 insertions(+), 16 deletions(-)

--
2.28.0.rc0.105.gf9edc3c819-goog

+21 -13
+21 -13
drivers/regulator/core.c
··· 105 105 static struct regulator *create_regulator(struct regulator_dev *rdev, 106 106 struct device *dev, 107 107 const char *supply_name); 108 + static void destroy_regulator(struct regulator *regulator); 108 109 static void _regulator_put(struct regulator *regulator); 109 110 110 111 const char *rdev_get_name(struct regulator_dev *rdev) ··· 2035 2034 } 2036 2035 EXPORT_SYMBOL_GPL(regulator_get_optional); 2037 2036 2038 - /* regulator_list_mutex lock held by regulator_put() */ 2039 - static void _regulator_put(struct regulator *regulator) 2037 + static void destroy_regulator(struct regulator *regulator) 2040 2038 { 2041 - struct regulator_dev *rdev; 2042 - 2043 - if (IS_ERR_OR_NULL(regulator)) 2044 - return; 2045 - 2046 - lockdep_assert_held_once(&regulator_list_mutex); 2047 - 2048 - /* Docs say you must disable before calling regulator_put() */ 2049 - WARN_ON(regulator->enable_count); 2050 - 2051 - rdev = regulator->rdev; 2039 + struct regulator_dev *rdev = regulator->rdev; 2052 2040 2053 2041 debugfs_remove_recursive(regulator->debugfs); 2054 2042 ··· 2058 2068 2059 2069 kfree_const(regulator->supply_name); 2060 2070 kfree(regulator); 2071 + } 2072 + 2073 + /* regulator_list_mutex lock held by regulator_put() */ 2074 + static void _regulator_put(struct regulator *regulator) 2075 + { 2076 + struct regulator_dev *rdev; 2077 + 2078 + if (IS_ERR_OR_NULL(regulator)) 2079 + return; 2080 + 2081 + lockdep_assert_held_once(&regulator_list_mutex); 2082 + 2083 + /* Docs say you must disable before calling regulator_put() */ 2084 + WARN_ON(regulator->enable_count); 2085 + 2086 + rdev = regulator->rdev; 2087 + 2088 + destroy_regulator(regulator); 2061 2089 2062 2090 module_put(rdev->owner); 2063 2091 put_device(&rdev->dev);