2 * otg.c - ChipIdea USB IP core OTG driver
4 * Copyright (C) 2013 Freescale Semiconductor, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
14 * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP
18 #include <linux/usb/otg.h>
19 #include <linux/usb/gadget.h>
20 #include <linux/usb/chipidea.h>
28 * hw_read_otgsc returns otgsc register bits value.
29 * @mask: bitfield mask
31 u32
hw_read_otgsc(struct ci_hdrc
*ci
, u32 mask
)
33 struct ci_hdrc_cable
*cable
;
34 u32 val
= hw_read(ci
, OP_OTGSC
, mask
);
37 * If using extcon framework for VBUS and/or ID signal
38 * detection overwrite OTGSC register value
40 cable
= &ci
->platdata
->vbus_extcon
;
41 if (!IS_ERR(cable
->edev
)) {
58 cable
= &ci
->platdata
->id_extcon
;
59 if (!IS_ERR(cable
->edev
)) {
80 * hw_write_otgsc updates target bits of OTGSC register.
81 * @mask: bitfield mask
82 * @data: to be written
84 void hw_write_otgsc(struct ci_hdrc
*ci
, u32 mask
, u32 data
)
86 struct ci_hdrc_cable
*cable
;
88 cable
= &ci
->platdata
->vbus_extcon
;
89 if (!IS_ERR(cable
->edev
)) {
90 if (data
& mask
& OTGSC_BSVIS
)
91 cable
->changed
= false;
93 /* Don't enable vbus interrupt if using external notifier */
94 if (data
& mask
& OTGSC_BSVIE
) {
95 cable
->enabled
= true;
97 } else if (mask
& OTGSC_BSVIE
) {
98 cable
->enabled
= false;
102 cable
= &ci
->platdata
->id_extcon
;
103 if (!IS_ERR(cable
->edev
)) {
104 if (data
& mask
& OTGSC_IDIS
)
105 cable
->changed
= false;
107 /* Don't enable id interrupt if using external notifier */
108 if (data
& mask
& OTGSC_IDIE
) {
109 cable
->enabled
= true;
111 } else if (mask
& OTGSC_IDIE
) {
112 cable
->enabled
= false;
116 hw_write(ci
, OP_OTGSC
, mask
| OTGSC_INT_STATUS_BITS
, data
);
120 * ci_otg_role - pick role based on ID pin state
121 * @ci: the controller
123 enum ci_role
ci_otg_role(struct ci_hdrc
*ci
)
125 enum ci_role role
= hw_read_otgsc(ci
, OTGSC_ID
)
132 void ci_handle_vbus_change(struct ci_hdrc
*ci
)
137 if (hw_read_otgsc(ci
, OTGSC_BSV
) && !ci
->vbus_active
)
138 usb_gadget_vbus_connect(&ci
->gadget
);
139 else if (!hw_read_otgsc(ci
, OTGSC_BSV
) && ci
->vbus_active
)
140 usb_gadget_vbus_disconnect(&ci
->gadget
);
144 * When we switch to device mode, the vbus value should be lower
145 * than OTGSC_BSV before connecting to host.
147 * @ci: the controller
149 * This function returns an error code if timeout
151 static int hw_wait_vbus_lower_bsv(struct ci_hdrc
*ci
)
153 unsigned long elapse
= jiffies
+ msecs_to_jiffies(5000);
154 u32 mask
= OTGSC_BSV
;
156 while (hw_read_otgsc(ci
, mask
)) {
157 if (time_after(jiffies
, elapse
)) {
158 dev_err(ci
->dev
, "timeout waiting for %08x in OTGSC\n",
168 static void ci_handle_id_switch(struct ci_hdrc
*ci
)
170 enum ci_role role
= ci_otg_role(ci
);
172 if (role
!= ci
->role
) {
173 dev_dbg(ci
->dev
, "switching from %s to %s\n",
174 ci_role(ci
)->name
, ci
->roles
[role
]->name
);
178 if (role
== CI_ROLE_GADGET
&&
179 IS_ERR(ci
->platdata
->vbus_extcon
.edev
))
181 * Wait vbus lower than OTGSC_BSV before connecting
182 * to host. If connecting status is from an external
183 * connector instead of register, we don't need to
184 * care vbus on the board, since it will not affect
185 * external connector status.
187 hw_wait_vbus_lower_bsv(ci
);
189 ci_role_start(ci
, role
);
190 /* vbus change may have already occurred */
191 if (role
== CI_ROLE_GADGET
)
192 ci_handle_vbus_change(ci
);
196 * ci_otg_work - perform otg (vbus/id) event handle
199 static void ci_otg_work(struct work_struct
*work
)
201 struct ci_hdrc
*ci
= container_of(work
, struct ci_hdrc
, work
);
203 if (ci_otg_is_fsm_mode(ci
) && !ci_otg_fsm_work(ci
)) {
208 pm_runtime_get_sync(ci
->dev
);
210 ci
->id_event
= false;
211 ci_handle_id_switch(ci
);
212 } else if (ci
->b_sess_valid_event
) {
213 ci
->b_sess_valid_event
= false;
214 ci_handle_vbus_change(ci
);
216 dev_err(ci
->dev
, "unexpected event occurs at %s\n", __func__
);
217 pm_runtime_put_sync(ci
->dev
);
224 * ci_hdrc_otg_init - initialize otg struct
227 int ci_hdrc_otg_init(struct ci_hdrc
*ci
)
229 INIT_WORK(&ci
->work
, ci_otg_work
);
230 ci
->wq
= create_freezable_workqueue("ci_otg");
232 dev_err(ci
->dev
, "can't create workqueue\n");
236 if (ci_otg_is_fsm_mode(ci
))
237 return ci_hdrc_otg_fsm_init(ci
);
243 * ci_hdrc_otg_destroy - destroy otg struct
246 void ci_hdrc_otg_destroy(struct ci_hdrc
*ci
)
249 flush_workqueue(ci
->wq
);
250 destroy_workqueue(ci
->wq
);
252 /* Disable all OTG irq and clear status */
253 hw_write_otgsc(ci
, OTGSC_INT_EN_BITS
| OTGSC_INT_STATUS_BITS
,
254 OTGSC_INT_STATUS_BITS
);
255 if (ci_otg_is_fsm_mode(ci
))
256 ci_hdrc_otg_fsm_remove(ci
);