summaryrefslogtreecommitdiff
path: root/include/linux/device.h
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-03-26 10:33:38 +0000
committerMark Brown <broonie@kernel.org>2026-03-26 10:33:38 +0000
commitc6eea4ff846ed342a12cedf3af730a6204a8d97e (patch)
treea90915646bde640e17fdc16ce17674222d9f4c84 /include/linux/device.h
parentc673efd5db2223c2e8b885025bcd96bca6cdb171 (diff)
parentbfe6a264effcb6fe99ad7ceaf9e8c7439fc9555b (diff)
ASoC: adau1372: Fix error handling in adau1372_set_power()
Jihed Chaibi <jihed.chaibi.dev@gmail.com> says: adau1372_set_power() had two related error handling issues in its enable path: clk_prepare_enable() was called but its return value discarded, and adau1372_enable_pll() was a void function that silently swallowed lock failures, leaving mclk enabled and adau1372->enabled set to true despite the device being in a broken state. Patch 1 fixes the unchecked clk_prepare_enable() by making adau1372_set_power() return int and propagating the error. Patch 2 converts adau1372_enable_pll() to return int and adds a full unwind in adau1372_set_power() if PLL lock fails, reversing the regcache, GPIO power-down, and clock state.
Diffstat (limited to 'include/linux/device.h')
-rw-r--r--include/linux/device.h54
1 files changed, 54 insertions, 0 deletions
diff --git a/include/linux/device.h b/include/linux/device.h
index 0be95294b6e6..e65d564f01cd 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -483,6 +483,8 @@ struct device_physical_location {
* on. This shrinks the "Board Support Packages" (BSPs) and
* minimizes board-specific #ifdefs in drivers.
* @driver_data: Private pointer for driver specific info.
+ * @driver_override: Driver name to force a match. Do not touch directly; use
+ * device_set_driver_override() instead.
* @links: Links to suppliers and consumers of this device.
* @power: For device power management.
* See Documentation/driver-api/pm/devices.rst for details.
@@ -576,6 +578,10 @@ struct device {
core doesn't touch it */
void *driver_data; /* Driver data, set and get with
dev_set_drvdata/dev_get_drvdata */
+ struct {
+ const char *name;
+ spinlock_t lock;
+ } driver_override;
struct mutex mutex; /* mutex to synchronize calls to
* its driver.
*/
@@ -701,6 +707,54 @@ struct device_link {
#define kobj_to_dev(__kobj) container_of_const(__kobj, struct device, kobj)
+int __device_set_driver_override(struct device *dev, const char *s, size_t len);
+
+/**
+ * device_set_driver_override() - Helper to set or clear driver override.
+ * @dev: Device to change
+ * @s: NUL-terminated string, new driver name to force a match, pass empty
+ * string to clear it ("" or "\n", where the latter is only for sysfs
+ * interface).
+ *
+ * Helper to set or clear driver override of a device.
+ *
+ * Returns: 0 on success or a negative error code on failure.
+ */
+static inline int device_set_driver_override(struct device *dev, const char *s)
+{
+ return __device_set_driver_override(dev, s, s ? strlen(s) : 0);
+}
+
+/**
+ * device_has_driver_override() - Check if a driver override has been set.
+ * @dev: device to check
+ *
+ * Returns true if a driver override has been set for this device.
+ */
+static inline bool device_has_driver_override(struct device *dev)
+{
+ guard(spinlock)(&dev->driver_override.lock);
+ return !!dev->driver_override.name;
+}
+
+/**
+ * device_match_driver_override() - Match a driver against the device's driver_override.
+ * @dev: device to check
+ * @drv: driver to match against
+ *
+ * Returns > 0 if a driver override is set and matches the given driver, 0 if a
+ * driver override is set but does not match, or < 0 if a driver override is not
+ * set at all.
+ */
+static inline int device_match_driver_override(struct device *dev,
+ const struct device_driver *drv)
+{
+ guard(spinlock)(&dev->driver_override.lock);
+ if (dev->driver_override.name)
+ return !strcmp(dev->driver_override.name, drv->name);
+ return -1;
+}
+
/**
* device_iommu_mapped - Returns true when the device DMA is translated
* by an IOMMU