summaryrefslogtreecommitdiffstats
path: root/drivers/usb/common
diff options
context:
space:
mode:
authorLi Jun <jun.li@nxp.com>2016-02-18 21:04:42 -0500
committerFelipe Balbi <balbi@kernel.org>2016-03-04 08:14:36 -0500
commitae57e97a95211397b46a40f8cb0a23966c054bc5 (patch)
tree3d6f2248f4edb3e5d1e5d3ea19b9c8ea97862ac3 /drivers/usb/common
parent346dbc69933086312d9e76bb68ba04e2c82c9b13 (diff)
usb: common: otg-fsm: add HNP polling support
Adds HNP polling timer when transits to host state, the OTG status request will be sent to peripheral after timeout, if host request flag is set, it will switch to peripheral state, otherwise it will repeat HNP polling every 1.5s and maintain the current session. Acked-by: Peter Chen <peter.chen@nxp.com> Signed-off-by: Li Jun <jun.li@nxp.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
Diffstat (limited to 'drivers/usb/common')
-rw-r--r--drivers/usb/common/usb-otg-fsm.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/usb/common/usb-otg-fsm.c b/drivers/usb/common/usb-otg-fsm.c
index 61d538aa2346..504708f59b93 100644
--- a/drivers/usb/common/usb-otg-fsm.c
+++ b/drivers/usb/common/usb-otg-fsm.c
@@ -78,6 +78,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
78 fsm->b_srp_done = 0; 78 fsm->b_srp_done = 0;
79 break; 79 break;
80 case OTG_STATE_B_PERIPHERAL: 80 case OTG_STATE_B_PERIPHERAL:
81 if (fsm->otg->gadget)
82 fsm->otg->gadget->host_request_flag = 0;
81 break; 83 break;
82 case OTG_STATE_B_WAIT_ACON: 84 case OTG_STATE_B_WAIT_ACON:
83 otg_del_timer(fsm, B_ASE0_BRST); 85 otg_del_timer(fsm, B_ASE0_BRST);
@@ -107,6 +109,8 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
107 case OTG_STATE_A_PERIPHERAL: 109 case OTG_STATE_A_PERIPHERAL:
108 otg_del_timer(fsm, A_BIDL_ADIS); 110 otg_del_timer(fsm, A_BIDL_ADIS);
109 fsm->a_bidl_adis_tmout = 0; 111 fsm->a_bidl_adis_tmout = 0;
112 if (fsm->otg->gadget)
113 fsm->otg->gadget->host_request_flag = 0;
110 break; 114 break;
111 case OTG_STATE_A_WAIT_VFALL: 115 case OTG_STATE_A_WAIT_VFALL:
112 otg_del_timer(fsm, A_WAIT_VFALL); 116 otg_del_timer(fsm, A_WAIT_VFALL);
@@ -120,6 +124,87 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
120 } 124 }
121} 125}
122 126
127static void otg_hnp_polling_work(struct work_struct *work)
128{
129 struct otg_fsm *fsm = container_of(to_delayed_work(work),
130 struct otg_fsm, hnp_polling_work);
131 struct usb_device *udev;
132 enum usb_otg_state state = fsm->otg->state;
133 u8 flag;
134 int retval;
135
136 if (state != OTG_STATE_A_HOST && state != OTG_STATE_B_HOST)
137 return;
138
139 udev = usb_hub_find_child(fsm->otg->host->root_hub, 1);
140 if (!udev) {
141 dev_err(fsm->otg->host->controller,
142 "no usb dev connected, can't start HNP polling\n");
143 return;
144 }
145
146 *fsm->host_req_flag = 0;
147 /* Get host request flag from connected USB device */
148 retval = usb_control_msg(udev,
149 usb_rcvctrlpipe(udev, 0),
150 USB_REQ_GET_STATUS,
151 USB_DIR_IN | USB_RECIP_DEVICE,
152 0,
153 OTG_STS_SELECTOR,
154 fsm->host_req_flag,
155 1,
156 USB_CTRL_GET_TIMEOUT);
157 if (retval != 1) {
158 dev_err(&udev->dev, "Get one byte OTG status failed\n");
159 return;
160 }
161
162 flag = *fsm->host_req_flag;
163 if (flag == 0) {
164 /* Continue HNP polling */
165 schedule_delayed_work(&fsm->hnp_polling_work,
166 msecs_to_jiffies(T_HOST_REQ_POLL));
167 return;
168 } else if (flag != HOST_REQUEST_FLAG) {
169 dev_err(&udev->dev, "host request flag %d is invalid\n", flag);
170 return;
171 }
172
173 /* Host request flag is set */
174 if (state == OTG_STATE_A_HOST) {
175 /* Set b_hnp_enable */
176 if (!fsm->otg->host->b_hnp_enable) {
177 retval = usb_control_msg(udev,
178 usb_sndctrlpipe(udev, 0),
179 USB_REQ_SET_FEATURE, 0,
180 USB_DEVICE_B_HNP_ENABLE,
181 0, NULL, 0,
182 USB_CTRL_SET_TIMEOUT);
183 if (retval >= 0)
184 fsm->otg->host->b_hnp_enable = 1;
185 }
186 fsm->a_bus_req = 0;
187 } else if (state == OTG_STATE_B_HOST) {
188 fsm->b_bus_req = 0;
189 }
190
191 otg_statemachine(fsm);
192}
193
194static void otg_start_hnp_polling(struct otg_fsm *fsm)
195{
196 /*
197 * The memory of host_req_flag should be allocated by
198 * controller driver, otherwise, hnp polling is not started.
199 */
200 if (!fsm->host_req_flag)
201 return;
202
203 INIT_DELAYED_WORK(&fsm->hnp_polling_work, otg_hnp_polling_work);
204 schedule_delayed_work(&fsm->hnp_polling_work,
205 msecs_to_jiffies(T_HOST_REQ_POLL));
206}
207
123/* Called when entering a state */ 208/* Called when entering a state */
124static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) 209static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
125{ 210{
@@ -169,6 +254,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
169 otg_set_protocol(fsm, PROTO_HOST); 254 otg_set_protocol(fsm, PROTO_HOST);
170 usb_bus_start_enum(fsm->otg->host, 255 usb_bus_start_enum(fsm->otg->host,
171 fsm->otg->host->otg_port); 256 fsm->otg->host->otg_port);
257 otg_start_hnp_polling(fsm);
172 break; 258 break;
173 case OTG_STATE_A_IDLE: 259 case OTG_STATE_A_IDLE:
174 otg_drv_vbus(fsm, 0); 260 otg_drv_vbus(fsm, 0);
@@ -203,6 +289,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
203 */ 289 */
204 if (!fsm->a_bus_req || fsm->a_suspend_req_inf) 290 if (!fsm->a_bus_req || fsm->a_suspend_req_inf)
205 otg_add_timer(fsm, A_WAIT_ENUM); 291 otg_add_timer(fsm, A_WAIT_ENUM);
292 otg_start_hnp_polling(fsm);
206 break; 293 break;
207 case OTG_STATE_A_SUSPEND: 294 case OTG_STATE_A_SUSPEND:
208 otg_drv_vbus(fsm, 1); 295 otg_drv_vbus(fsm, 1);