1 --- a/drivers/bus/mhi/host/init.c
2 +++ b/drivers/bus/mhi/host/init.c
3 @@ -43,6 +43,7 @@ const char * const dev_state_tran_str[DE
4 [DEV_ST_TRANSITION_FP] = "FLASH PROGRAMMER",
5 [DEV_ST_TRANSITION_SYS_ERR] = "SYS ERROR",
6 [DEV_ST_TRANSITION_DISABLE] = "DISABLE",
7 + [DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE] = "DISABLE (DESTROY DEVICE)",
10 const char * const mhi_ch_state_type_str[MHI_CH_STATE_TYPE_MAX] = {
11 --- a/drivers/bus/mhi/host/internal.h
12 +++ b/drivers/bus/mhi/host/internal.h
13 @@ -69,6 +69,7 @@ enum dev_st_transition {
15 DEV_ST_TRANSITION_SYS_ERR,
16 DEV_ST_TRANSITION_DISABLE,
17 + DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE,
18 DEV_ST_TRANSITION_MAX,
21 --- a/drivers/bus/mhi/host/pm.c
22 +++ b/drivers/bus/mhi/host/pm.c
23 @@ -466,7 +466,8 @@ error_mission_mode:
26 /* Handle shutdown transitions */
27 -static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl)
28 +static void mhi_pm_disable_transition(struct mhi_controller *mhi_cntrl,
29 + bool destroy_device)
31 enum mhi_pm_state cur_state;
32 struct mhi_event *mhi_event;
33 @@ -528,8 +529,16 @@ skip_mhi_reset:
34 dev_dbg(dev, "Waiting for all pending threads to complete\n");
35 wake_up_all(&mhi_cntrl->state_event);
37 - dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
38 - device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
40 + * Only destroy the 'struct device' for channels if indicated by the
41 + * 'destroy_device' flag. Because, during system suspend or hibernation
42 + * state, there is no need to destroy the 'struct device' as the endpoint
43 + * device would still be physically attached to the machine.
45 + if (destroy_device) {
46 + dev_dbg(dev, "Reset all active channels and remove MHI devices\n");
47 + device_for_each_child(&mhi_cntrl->mhi_dev->dev, NULL, mhi_destroy_device);
50 mutex_lock(&mhi_cntrl->pm_mutex);
52 @@ -820,7 +829,10 @@ void mhi_pm_st_worker(struct work_struct
53 mhi_pm_sys_error_transition(mhi_cntrl);
55 case DEV_ST_TRANSITION_DISABLE:
56 - mhi_pm_disable_transition(mhi_cntrl);
57 + mhi_pm_disable_transition(mhi_cntrl, false);
59 + case DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE:
60 + mhi_pm_disable_transition(mhi_cntrl, true);
64 @@ -1174,7 +1186,8 @@ error_exit:
66 EXPORT_SYMBOL_GPL(mhi_async_power_up);
68 -void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
69 +static void __mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful,
70 + bool destroy_device)
72 enum mhi_pm_state cur_state, transition_state;
73 struct device *dev = &mhi_cntrl->mhi_dev->dev;
74 @@ -1210,15 +1223,32 @@ void mhi_power_down(struct mhi_controlle
75 write_unlock_irq(&mhi_cntrl->pm_lock);
76 mutex_unlock(&mhi_cntrl->pm_mutex);
78 - mhi_queue_state_transition(mhi_cntrl, DEV_ST_TRANSITION_DISABLE);
80 + mhi_queue_state_transition(mhi_cntrl,
81 + DEV_ST_TRANSITION_DISABLE_DESTROY_DEVICE);
83 + mhi_queue_state_transition(mhi_cntrl,
84 + DEV_ST_TRANSITION_DISABLE);
86 /* Wait for shutdown to complete */
87 flush_work(&mhi_cntrl->st_worker);
89 disable_irq(mhi_cntrl->irq[0]);
92 +void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful)
94 + __mhi_power_down(mhi_cntrl, graceful, true);
96 EXPORT_SYMBOL_GPL(mhi_power_down);
98 +void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl,
101 + __mhi_power_down(mhi_cntrl, graceful, false);
103 +EXPORT_SYMBOL_GPL(mhi_power_down_keep_dev);
105 int mhi_sync_power_up(struct mhi_controller *mhi_cntrl)
107 int ret = mhi_async_power_up(mhi_cntrl);
108 --- a/include/linux/mhi.h
109 +++ b/include/linux/mhi.h
110 @@ -649,13 +649,29 @@ int mhi_async_power_up(struct mhi_contro
111 int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
114 - * mhi_power_down - Start MHI power down sequence
115 + * mhi_power_down - Power down the MHI device and also destroy the
116 + * 'struct device' for the channels associated with it.
117 + * See also mhi_power_down_keep_dev() which is a variant
118 + * of this API that keeps the 'struct device' for channels
119 + * (useful during suspend/hibernation).
120 * @mhi_cntrl: MHI controller
121 * @graceful: Link is still accessible, so do a graceful shutdown process
123 void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
126 + * mhi_power_down_keep_dev - Power down the MHI device but keep the 'struct
127 + * device' for the channels associated with it.
128 + * This is a variant of 'mhi_power_down()' and
129 + * useful in scenarios such as suspend/hibernation
130 + * where destroying of the 'struct device' is not
132 + * @mhi_cntrl: MHI controller
133 + * @graceful: Link is still accessible, so do a graceful shutdown process
135 +void mhi_power_down_keep_dev(struct mhi_controller *mhi_cntrl, bool graceful);
138 * mhi_unprepare_after_power_down - Free any allocated memory after power down
139 * @mhi_cntrl: MHI controller