1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-1.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Renesas USB driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2011 Renesas Solutions Corp.
6*4882a593Smuzhiyun * Copyright (C) 2019 Renesas Electronics Corporation
7*4882a593Smuzhiyun * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun #include <linux/interrupt.h>
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include "common.h"
12*4882a593Smuzhiyun #include "mod.h"
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun * autonomy
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * these functions are used if platform doesn't have external phy.
18*4882a593Smuzhiyun * -> there is no "notify_hotplug" callback from platform
19*4882a593Smuzhiyun * -> call "notify_hotplug" by itself
20*4882a593Smuzhiyun * -> use own interrupt to connect/disconnect
21*4882a593Smuzhiyun * -> it mean module clock is always ON
22*4882a593Smuzhiyun * ~~~~~~~~~~~~~~~~~~~~~~~~~
23*4882a593Smuzhiyun */
usbhsm_autonomy_get_vbus(struct platform_device * pdev)24*4882a593Smuzhiyun static int usbhsm_autonomy_get_vbus(struct platform_device *pdev)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun return VBSTS & usbhs_read(priv, INTSTS0);
29*4882a593Smuzhiyun }
30*4882a593Smuzhiyun
usbhsm_autonomy_irq_vbus(struct usbhs_priv * priv,struct usbhs_irq_state * irq_state)31*4882a593Smuzhiyun static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
32*4882a593Smuzhiyun struct usbhs_irq_state *irq_state)
33*4882a593Smuzhiyun {
34*4882a593Smuzhiyun struct platform_device *pdev = usbhs_priv_to_pdev(priv);
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun usbhsc_schedule_notify_hotplug(pdev);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return 0;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
usbhs_mod_autonomy_mode(struct usbhs_priv * priv)41*4882a593Smuzhiyun void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun info->irq_vbus = usbhsm_autonomy_irq_vbus;
46*4882a593Smuzhiyun info->get_vbus = usbhsm_autonomy_get_vbus;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun usbhs_irq_callback_update(priv, NULL);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
usbhs_mod_non_autonomy_mode(struct usbhs_priv * priv)51*4882a593Smuzhiyun void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun info->get_vbus = priv->pfunc->get_vbus;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /*
59*4882a593Smuzhiyun * host / gadget functions
60*4882a593Smuzhiyun *
61*4882a593Smuzhiyun * renesas_usbhs host/gadget can register itself by below functions.
62*4882a593Smuzhiyun * these functions are called when probe
63*4882a593Smuzhiyun *
64*4882a593Smuzhiyun */
usbhs_mod_register(struct usbhs_priv * priv,struct usbhs_mod * mod,int id)65*4882a593Smuzhiyun void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun info->mod[id] = mod;
70*4882a593Smuzhiyun mod->priv = priv;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
usbhs_mod_get(struct usbhs_priv * priv,int id)73*4882a593Smuzhiyun struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
76*4882a593Smuzhiyun struct usbhs_mod *ret = NULL;
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun switch (id) {
79*4882a593Smuzhiyun case USBHS_HOST:
80*4882a593Smuzhiyun case USBHS_GADGET:
81*4882a593Smuzhiyun ret = info->mod[id];
82*4882a593Smuzhiyun break;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return ret;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
usbhs_mod_is_host(struct usbhs_priv * priv)88*4882a593Smuzhiyun int usbhs_mod_is_host(struct usbhs_priv *priv)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun struct usbhs_mod *mod = usbhs_mod_get_current(priv);
91*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun if (!mod)
94*4882a593Smuzhiyun return -EINVAL;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun return info->mod[USBHS_HOST] == mod;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
usbhs_mod_get_current(struct usbhs_priv * priv)99*4882a593Smuzhiyun struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return info->curt;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
usbhs_mod_change(struct usbhs_priv * priv,int id)106*4882a593Smuzhiyun int usbhs_mod_change(struct usbhs_priv *priv, int id)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
109*4882a593Smuzhiyun struct usbhs_mod *mod = NULL;
110*4882a593Smuzhiyun int ret = 0;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun /* id < 0 mean no current */
113*4882a593Smuzhiyun switch (id) {
114*4882a593Smuzhiyun case USBHS_HOST:
115*4882a593Smuzhiyun case USBHS_GADGET:
116*4882a593Smuzhiyun mod = info->mod[id];
117*4882a593Smuzhiyun break;
118*4882a593Smuzhiyun default:
119*4882a593Smuzhiyun ret = -EINVAL;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun info->curt = mod;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun return ret;
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun static irqreturn_t usbhs_interrupt(int irq, void *data);
usbhs_mod_probe(struct usbhs_priv * priv)127*4882a593Smuzhiyun int usbhs_mod_probe(struct usbhs_priv *priv)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun struct device *dev = usbhs_priv_to_dev(priv);
130*4882a593Smuzhiyun int ret;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun * install host/gadget driver
134*4882a593Smuzhiyun */
135*4882a593Smuzhiyun ret = usbhs_mod_host_probe(priv);
136*4882a593Smuzhiyun if (ret < 0)
137*4882a593Smuzhiyun return ret;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun ret = usbhs_mod_gadget_probe(priv);
140*4882a593Smuzhiyun if (ret < 0)
141*4882a593Smuzhiyun goto mod_init_host_err;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /* irq settings */
144*4882a593Smuzhiyun ret = devm_request_irq(dev, priv->irq, usbhs_interrupt,
145*4882a593Smuzhiyun priv->irqflags, dev_name(dev), priv);
146*4882a593Smuzhiyun if (ret) {
147*4882a593Smuzhiyun dev_err(dev, "irq request err\n");
148*4882a593Smuzhiyun goto mod_init_gadget_err;
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun return ret;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun mod_init_gadget_err:
154*4882a593Smuzhiyun usbhs_mod_gadget_remove(priv);
155*4882a593Smuzhiyun mod_init_host_err:
156*4882a593Smuzhiyun usbhs_mod_host_remove(priv);
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return ret;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
usbhs_mod_remove(struct usbhs_priv * priv)161*4882a593Smuzhiyun void usbhs_mod_remove(struct usbhs_priv *priv)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun usbhs_mod_host_remove(priv);
164*4882a593Smuzhiyun usbhs_mod_gadget_remove(priv);
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * status functions
169*4882a593Smuzhiyun */
usbhs_status_get_device_state(struct usbhs_irq_state * irq_state)170*4882a593Smuzhiyun int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun return (int)irq_state->intsts0 & DVSQ_MASK;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
usbhs_status_get_ctrl_stage(struct usbhs_irq_state * irq_state)175*4882a593Smuzhiyun int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * return value
179*4882a593Smuzhiyun *
180*4882a593Smuzhiyun * IDLE_SETUP_STAGE
181*4882a593Smuzhiyun * READ_DATA_STAGE
182*4882a593Smuzhiyun * READ_STATUS_STAGE
183*4882a593Smuzhiyun * WRITE_DATA_STAGE
184*4882a593Smuzhiyun * WRITE_STATUS_STAGE
185*4882a593Smuzhiyun * NODATA_STATUS_STAGE
186*4882a593Smuzhiyun * SEQUENCE_ERROR
187*4882a593Smuzhiyun */
188*4882a593Smuzhiyun return (int)irq_state->intsts0 & CTSQ_MASK;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
usbhs_status_get_each_irq(struct usbhs_priv * priv,struct usbhs_irq_state * state)191*4882a593Smuzhiyun static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
192*4882a593Smuzhiyun struct usbhs_irq_state *state)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun struct usbhs_mod *mod = usbhs_mod_get_current(priv);
195*4882a593Smuzhiyun u16 intenb0, intenb1;
196*4882a593Smuzhiyun unsigned long flags;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun /******************** spin lock ********************/
199*4882a593Smuzhiyun usbhs_lock(priv, flags);
200*4882a593Smuzhiyun state->intsts0 = usbhs_read(priv, INTSTS0);
201*4882a593Smuzhiyun intenb0 = usbhs_read(priv, INTENB0);
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun if (usbhs_mod_is_host(priv)) {
204*4882a593Smuzhiyun state->intsts1 = usbhs_read(priv, INTSTS1);
205*4882a593Smuzhiyun intenb1 = usbhs_read(priv, INTENB1);
206*4882a593Smuzhiyun } else {
207*4882a593Smuzhiyun state->intsts1 = intenb1 = 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun /* mask */
211*4882a593Smuzhiyun if (mod) {
212*4882a593Smuzhiyun state->brdysts = usbhs_read(priv, BRDYSTS);
213*4882a593Smuzhiyun state->nrdysts = usbhs_read(priv, NRDYSTS);
214*4882a593Smuzhiyun state->bempsts = usbhs_read(priv, BEMPSTS);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun state->bempsts &= mod->irq_bempsts;
217*4882a593Smuzhiyun state->brdysts &= mod->irq_brdysts;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun usbhs_unlock(priv, flags);
220*4882a593Smuzhiyun /******************** spin unlock ******************/
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /*
223*4882a593Smuzhiyun * Check whether the irq enable registers and the irq status are set
224*4882a593Smuzhiyun * when IRQF_SHARED is set.
225*4882a593Smuzhiyun */
226*4882a593Smuzhiyun if (priv->irqflags & IRQF_SHARED) {
227*4882a593Smuzhiyun if (!(intenb0 & state->intsts0) &&
228*4882a593Smuzhiyun !(intenb1 & state->intsts1) &&
229*4882a593Smuzhiyun !(state->bempsts) &&
230*4882a593Smuzhiyun !(state->brdysts))
231*4882a593Smuzhiyun return -EIO;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun return 0;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun /*
238*4882a593Smuzhiyun * interrupt
239*4882a593Smuzhiyun */
240*4882a593Smuzhiyun #define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */
241*4882a593Smuzhiyun #define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */
usbhs_interrupt(int irq,void * data)242*4882a593Smuzhiyun static irqreturn_t usbhs_interrupt(int irq, void *data)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct usbhs_priv *priv = data;
245*4882a593Smuzhiyun struct usbhs_irq_state irq_state;
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
248*4882a593Smuzhiyun return IRQ_NONE;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun * clear interrupt
252*4882a593Smuzhiyun *
253*4882a593Smuzhiyun * The hardware is _very_ picky to clear interrupt bit.
254*4882a593Smuzhiyun * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value.
255*4882a593Smuzhiyun *
256*4882a593Smuzhiyun * see
257*4882a593Smuzhiyun * "Operation"
258*4882a593Smuzhiyun * - "Control Transfer (DCP)"
259*4882a593Smuzhiyun * - Function :: VALID bit should 0
260*4882a593Smuzhiyun */
261*4882a593Smuzhiyun usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
262*4882a593Smuzhiyun if (usbhs_mod_is_host(priv))
263*4882a593Smuzhiyun usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
264*4882a593Smuzhiyun
265*4882a593Smuzhiyun /*
266*4882a593Smuzhiyun * The driver should not clear the xxxSTS after the line of
267*4882a593Smuzhiyun * "call irq callback functions" because each "if" statement is
268*4882a593Smuzhiyun * possible to call the callback function for avoiding any side effects.
269*4882a593Smuzhiyun */
270*4882a593Smuzhiyun if (irq_state.intsts0 & BRDY)
271*4882a593Smuzhiyun usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
272*4882a593Smuzhiyun usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
273*4882a593Smuzhiyun if (irq_state.intsts0 & BEMP)
274*4882a593Smuzhiyun usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /*
277*4882a593Smuzhiyun * call irq callback functions
278*4882a593Smuzhiyun * see also
279*4882a593Smuzhiyun * usbhs_irq_setting_update
280*4882a593Smuzhiyun */
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* INTSTS0 */
283*4882a593Smuzhiyun if (irq_state.intsts0 & VBINT)
284*4882a593Smuzhiyun usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (irq_state.intsts0 & DVST)
287*4882a593Smuzhiyun usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (irq_state.intsts0 & CTRT)
290*4882a593Smuzhiyun usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state);
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun if (irq_state.intsts0 & BEMP)
293*4882a593Smuzhiyun usbhs_mod_call(priv, irq_empty, priv, &irq_state);
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (irq_state.intsts0 & BRDY)
296*4882a593Smuzhiyun usbhs_mod_call(priv, irq_ready, priv, &irq_state);
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun if (usbhs_mod_is_host(priv)) {
299*4882a593Smuzhiyun /* INTSTS1 */
300*4882a593Smuzhiyun if (irq_state.intsts1 & ATTCH)
301*4882a593Smuzhiyun usbhs_mod_call(priv, irq_attch, priv, &irq_state);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (irq_state.intsts1 & DTCH)
304*4882a593Smuzhiyun usbhs_mod_call(priv, irq_dtch, priv, &irq_state);
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun if (irq_state.intsts1 & SIGN)
307*4882a593Smuzhiyun usbhs_mod_call(priv, irq_sign, priv, &irq_state);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun if (irq_state.intsts1 & SACK)
310*4882a593Smuzhiyun usbhs_mod_call(priv, irq_sack, priv, &irq_state);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun return IRQ_HANDLED;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
usbhs_irq_callback_update(struct usbhs_priv * priv,struct usbhs_mod * mod)315*4882a593Smuzhiyun void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun u16 intenb0 = 0;
318*4882a593Smuzhiyun u16 intenb1 = 0;
319*4882a593Smuzhiyun struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun /*
322*4882a593Smuzhiyun * BEMPENB/BRDYENB are picky.
323*4882a593Smuzhiyun * below method is required
324*4882a593Smuzhiyun *
325*4882a593Smuzhiyun * - clear INTSTS0
326*4882a593Smuzhiyun * - update BEMPENB/BRDYENB
327*4882a593Smuzhiyun * - update INTSTS0
328*4882a593Smuzhiyun */
329*4882a593Smuzhiyun usbhs_write(priv, INTENB0, 0);
330*4882a593Smuzhiyun if (usbhs_mod_is_host(priv))
331*4882a593Smuzhiyun usbhs_write(priv, INTENB1, 0);
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun usbhs_write(priv, BEMPENB, 0);
334*4882a593Smuzhiyun usbhs_write(priv, BRDYENB, 0);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /*
337*4882a593Smuzhiyun * see also
338*4882a593Smuzhiyun * usbhs_interrupt
339*4882a593Smuzhiyun */
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (info->irq_vbus)
342*4882a593Smuzhiyun intenb0 |= VBSE;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (mod) {
345*4882a593Smuzhiyun /*
346*4882a593Smuzhiyun * INTSTS0
347*4882a593Smuzhiyun */
348*4882a593Smuzhiyun if (mod->irq_ctrl_stage)
349*4882a593Smuzhiyun intenb0 |= CTRE;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun if (mod->irq_dev_state)
352*4882a593Smuzhiyun intenb0 |= DVSE;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if (mod->irq_empty && mod->irq_bempsts) {
355*4882a593Smuzhiyun usbhs_write(priv, BEMPENB, mod->irq_bempsts);
356*4882a593Smuzhiyun intenb0 |= BEMPE;
357*4882a593Smuzhiyun }
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun if (mod->irq_ready && mod->irq_brdysts) {
360*4882a593Smuzhiyun usbhs_write(priv, BRDYENB, mod->irq_brdysts);
361*4882a593Smuzhiyun intenb0 |= BRDYE;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun if (usbhs_mod_is_host(priv)) {
365*4882a593Smuzhiyun /*
366*4882a593Smuzhiyun * INTSTS1
367*4882a593Smuzhiyun */
368*4882a593Smuzhiyun if (mod->irq_attch)
369*4882a593Smuzhiyun intenb1 |= ATTCHE;
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (mod->irq_dtch)
372*4882a593Smuzhiyun intenb1 |= DTCHE;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (mod->irq_sign)
375*4882a593Smuzhiyun intenb1 |= SIGNE;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun if (mod->irq_sack)
378*4882a593Smuzhiyun intenb1 |= SACKE;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (intenb0)
383*4882a593Smuzhiyun usbhs_write(priv, INTENB0, intenb0);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (usbhs_mod_is_host(priv) && intenb1)
386*4882a593Smuzhiyun usbhs_write(priv, INTENB1, intenb1);
387*4882a593Smuzhiyun }
388