diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 54195530e97a..3ac4e40f07a0 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -305,3 +305,14 @@ Description:
 		Reports the runtime PM children usage count of a device, or
 		0 if the children will be ignored.
 
+What:		/sys/devices/.../power/conditional_skip
+Date:		Feburary 2024
+Contact:	Guan-Yu Lin <guanyulin@google.com>
+Description:
+		The /sys/devices/.../conditional_skip attribute provides a way
+		to selectively skip system-wide power transitions like
+		suspend-to-RAM or hibernation. To skip a specific transition,
+		write its corresponding value to this attribute. For skipping
+		multiple transitions, combine their values using a bitwise OR
+		and write the result to this attribute.
+
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index fadcd0379dc2..d507626c7892 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -1881,6 +1881,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
  */
 int dpm_prepare(pm_message_t state)
 {
+	struct list_head list;
 	int error = 0;
 
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
@@ -1900,12 +1901,26 @@ int dpm_prepare(pm_message_t state)
 	 */
 	device_block_probing();
 
+	INIT_LIST_HEAD(&list);
 	mutex_lock(&dpm_list_mtx);
 	while (!list_empty(&dpm_list) && !error) {
 		struct device *dev = to_device(dpm_list.next);
 
 		get_device(dev);
 
+		if (dev->power.conditional_skip_pm & state.event) {
+			dev_info(dev, "skip system PM transition (event = 0x%04x)\n",
+				 state.event);
+
+			if (!list_empty(&dev->power.entry))
+				list_move_tail(&dev->power.entry, &list);
+
+			mutex_unlock(&dpm_list_mtx);
+			put_device(dev);
+			mutex_lock(&dpm_list_mtx);
+			continue;
+		}
+
 		mutex_unlock(&dpm_list_mtx);
 
 		trace_device_pm_callback_start(dev, "", state.event);
@@ -1931,6 +1946,7 @@ int dpm_prepare(pm_message_t state)
 
 		mutex_lock(&dpm_list_mtx);
 	}
+	list_splice(&list, &dpm_list);
 	mutex_unlock(&dpm_list_mtx);
 	trace_suspend_resume(TPS("dpm_prepare"), state.event, false);
 	return error;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a1474fb67db9..1feacb01b1e9 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -610,6 +610,31 @@ static DEVICE_ATTR_RW(async);
 #endif /* CONFIG_PM_SLEEP */
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
 
+static ssize_t conditional_skip_show(struct device *dev,
+				     struct device_attribute *attr,
+				     char *buf)
+{
+	return sysfs_emit(buf, "0x%04x\n", dev->power.conditional_skip_pm);
+}
+
+static ssize_t conditional_skip_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t n)
+{
+	int ret;
+
+	if (kstrtoint(buf, 0, &ret))
+		return -EINVAL;
+
+	ret &= (PM_EVENT_FREEZE|PM_EVENT_SUSPEND|PM_EVENT_HIBERNATE);
+
+	dev->power.conditional_skip_pm = ret;
+
+	return n;
+}
+
+static DEVICE_ATTR_RW(conditional_skip);
+
 static struct attribute *power_attrs[] = {
 #ifdef CONFIG_PM_ADVANCED_DEBUG
 #ifdef CONFIG_PM_SLEEP
@@ -620,6 +645,7 @@ static struct attribute *power_attrs[] = {
 	&dev_attr_runtime_active_kids.attr,
 	&dev_attr_runtime_enabled.attr,
 #endif /* CONFIG_PM_ADVANCED_DEBUG */
+	&dev_attr_conditional_skip.attr,
 	NULL,
 };
 static const struct attribute_group pm_attr_group = {
diff --git a/include/linux/device.h b/include/linux/device.h
index 97c4b046c09d..f2c73dd00211 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -968,6 +968,13 @@ static inline void device_set_pm_not_required(struct device *dev)
 	dev->power.no_pm = true;
 }
 
+static inline void device_set_pm_conditional_skip(struct device *dev,
+						  int condition)
+{
+	condition &= (PM_EVENT_FREEZE|PM_EVENT_SUSPEND|PM_EVENT_HIBERNATE);
+	dev->power.conditional_skip_pm = condition;
+}
+
 static inline void dev_pm_syscore_device(struct device *dev, bool val)
 {
 #ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/pm.h b/include/linux/pm.h
index a2f3e53a8196..890c7a601c2a 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -713,6 +713,7 @@ struct dev_pm_info {
 	enum rpm_status		last_status;
 	int			runtime_error;
 	int			autosuspend_delay;
+	int			conditional_skip_pm;
 	u64			last_busy;
 	u64			active_time;
 	u64			suspended_time;
