aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLi Jun <B47624@freescale.com>2014-01-01 00:35:34 -0500
committerNitin Garg <nitin.garg@freescale.com>2014-04-16 12:02:34 -0400
commitc777a32b4bf03edb888bb5831f1af2a5a5d58472 (patch)
tree907bd24bb9fa0090ad6ec271c64a587ceedc8480
parent8e1d8d5e1bce096257e64625e27a2c3b6a50a151 (diff)
ENGR00307558-5 usb: chipidea: add OTG fsm operation functions implemenation.
Add OTG HNP and SRP operation functions implementation: - charge vbus - drive vbus - connection signaling - drive sof - start data pulse - add fsm timer - delete fsm timer - start host - start gadget Signed-off-by: Li Jun <b47624@freescale.com>
-rw-r--r--drivers/usb/chipidea/bits.h9
-rw-r--r--drivers/usb/chipidea/ci.h2
-rw-r--r--drivers/usb/chipidea/otg_fsm.c197
-rw-r--r--drivers/usb/chipidea/otg_fsm.h25
4 files changed, 233 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index aa82c8517bcd..49d2dc1ab476 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -44,9 +44,14 @@
44#define DEVICEADDR_USBADR (0x7FUL << 25) 44#define DEVICEADDR_USBADR (0x7FUL << 25)
45 45
46/* PORTSC */ 46/* PORTSC */
47#define PORTSC_CCS BIT(0)
48#define PORTSC_CSC BIT(1)
49#define PORTSC_PEC BIT(3)
50#define PORTSC_OCC BIT(5)
47#define PORTSC_FPR BIT(6) 51#define PORTSC_FPR BIT(6)
48#define PORTSC_SUSP BIT(7) 52#define PORTSC_SUSP BIT(7)
49#define PORTSC_HSP BIT(9) 53#define PORTSC_HSP BIT(9)
54#define PORTSC_PP BIT(12)
50#define PORTSC_PTC (0x0FUL << 16) 55#define PORTSC_PTC (0x0FUL << 16)
51#define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) 56#define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23))
52/* PTS and PTW for non lpm version only */ 57/* PTS and PTW for non lpm version only */
@@ -56,6 +61,9 @@
56#define PORTSC_PTW BIT(28) 61#define PORTSC_PTW BIT(28)
57#define PORTSC_STS BIT(29) 62#define PORTSC_STS BIT(29)
58 63
64#define PORTSC_W1C_BITS \
65 (PORTSC_CSC | PORTSC_PEC | PORTSC_OCC)
66
59/* DEVLC */ 67/* DEVLC */
60#define DEVLC_PFSC BIT(23) 68#define DEVLC_PFSC BIT(23)
61#define DEVLC_PSPD (0x03UL << 25) 69#define DEVLC_PSPD (0x03UL << 25)
@@ -72,6 +80,7 @@
72 80
73/* OTGSC */ 81/* OTGSC */
74#define OTGSC_IDPU BIT(5) 82#define OTGSC_IDPU BIT(5)
83#define OTGSC_HADP BIT(6)
75#define OTGSC_ID BIT(8) 84#define OTGSC_ID BIT(8)
76#define OTGSC_AVV BIT(9) 85#define OTGSC_AVV BIT(9)
77#define OTGSC_ASV BIT(10) 86#define OTGSC_ASV BIT(10)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 2120e6dc1ef7..cbd333edbec0 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -112,6 +112,7 @@ struct hw_bank {
112 * @role: current role 112 * @role: current role
113 * @is_otg: if the device is otg-capable 113 * @is_otg: if the device is otg-capable
114 * @fsm: otg finite state machine 114 * @fsm: otg finite state machine
115 * @fsm_timer: pointer to timer list of otg fsm
115 * @work: work for role changing 116 * @work: work for role changing
116 * @wq: workqueue thread 117 * @wq: workqueue thread
117 * @qh_pool: allocation pool for queue heads 118 * @qh_pool: allocation pool for queue heads
@@ -152,6 +153,7 @@ struct ci_hdrc {
152 enum ci_role role; 153 enum ci_role role;
153 bool is_otg; 154 bool is_otg;
154 struct otg_fsm fsm; 155 struct otg_fsm fsm;
156 struct ci_otg_fsm_timer_list *fsm_timer;
155 struct work_struct work; 157 struct work_struct work;
156 struct workqueue_struct *wq; 158 struct workqueue_struct *wq;
157 159
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index f4bb7c83b708..4a40399df9e9 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -19,12 +19,208 @@
19#include <linux/usb/gadget.h> 19#include <linux/usb/gadget.h>
20#include <linux/usb/hcd.h> 20#include <linux/usb/hcd.h>
21#include <linux/usb/chipidea.h> 21#include <linux/usb/chipidea.h>
22#include <linux/regulator/consumer.h>
22 23
23#include "ci.h" 24#include "ci.h"
24#include "bits.h" 25#include "bits.h"
25#include "otg.h" 26#include "otg.h"
26#include "otg_fsm.h" 27#include "otg_fsm.h"
27 28
29/*
30 * Add timer to active timer list
31 */
32static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t)
33{
34 struct ci_otg_fsm_timer *tmp_timer;
35 struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t];
36 struct list_head *active_timers = &ci->fsm_timer->active_timers;
37
38 if (t >= NUM_CI_OTG_FSM_TIMERS)
39 return;
40
41 /*
42 * Check if the timer is already in the active list,
43 * if so update timer count
44 */
45 list_for_each_entry(tmp_timer, active_timers, list)
46 if (tmp_timer == timer) {
47 timer->count = timer->expires;
48 return;
49 }
50
51 timer->count = timer->expires;
52 list_add_tail(&timer->list, active_timers);
53
54 /* Enable 1ms irq */
55 if (!(hw_read_otgsc(ci, OTGSC_1MSIE)))
56 hw_write_otgsc(ci, OTGSC_1MSIE, OTGSC_1MSIE);
57}
58
59/*
60 * Remove timer from active timer list
61 */
62static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t)
63{
64 struct ci_otg_fsm_timer *tmp_timer, *del_tmp;
65 struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t];
66 struct list_head *active_timers = &ci->fsm_timer->active_timers;
67
68 if (t >= NUM_CI_OTG_FSM_TIMERS)
69 return;
70
71 list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list)
72 if (tmp_timer == timer)
73 list_del(&timer->list);
74
75 /* Disable 1ms irq if there is no any active timer */
76 if (list_empty(active_timers))
77 hw_write_otgsc(ci, OTGSC_1MSIE, 0);
78}
79
80/* -------------------------------------------------------------*/
81/* Operations that will be called from OTG Finite State Machine */
82/* -------------------------------------------------------------*/
83static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
84{
85 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
86
87 if (t < NUM_OTG_FSM_TIMERS)
88 ci_otg_add_timer(ci, t);
89 return;
90}
91
92static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
93{
94 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
95
96 if (t < NUM_OTG_FSM_TIMERS)
97 ci_otg_del_timer(ci, t);
98 return;
99}
100
101/*
102 * A-device drive vbus: turn on vbus regulator and enable port power
103 * Data pulse irq should be disabled while vbus is on.
104 */
105static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on)
106{
107 int ret;
108 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
109
110 if (on) {
111 /* Enable power power */
112 hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
113 PORTSC_PP);
114 if (ci->platdata->reg_vbus) {
115 ret = regulator_enable(ci->platdata->reg_vbus);
116 if (ret) {
117 dev_err(ci->dev,
118 "Failed to enable vbus regulator, ret=%d\n",
119 ret);
120 return;
121 }
122 }
123 /* Disable data pulse irq */
124 hw_write_otgsc(ci, OTGSC_DPIE, 0);
125
126 fsm->a_srp_det = 0;
127 fsm->power_up = 0;
128 } else {
129 if (ci->platdata->reg_vbus)
130 regulator_disable(ci->platdata->reg_vbus);
131
132 fsm->a_bus_drop = 1;
133 fsm->a_bus_req = 0;
134 }
135}
136
137/*
138 * Control data line by Run Stop bit.
139 */
140static void ci_otg_loc_conn(struct otg_fsm *fsm, int on)
141{
142 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
143
144 if (on)
145 hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
146 else
147 hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
148}
149
150/*
151 * Generate SOF by host.
152 * This is controlled through suspend/resume the port.
153 * In host mode, controller will automatically send SOF.
154 * Suspend will block the data on the port.
155 */
156static void ci_otg_loc_sof(struct otg_fsm *fsm, int on)
157{
158 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
159
160 if (on)
161 hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_FPR,
162 PORTSC_FPR);
163 else
164 hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_SUSP,
165 PORTSC_SUSP);
166}
167
168/*
169 * Start SRP pulsing by data-line pulsing,
170 * no v-bus pulsing followed
171 */
172static void ci_otg_start_pulse(struct otg_fsm *fsm)
173{
174 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
175
176 /* Hardware Assistant Data pulse */
177 hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP);
178
179 ci_otg_add_timer(ci, B_DATA_PLS);
180}
181
182static int ci_otg_start_host(struct otg_fsm *fsm, int on)
183{
184 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
185
186 mutex_unlock(&fsm->lock);
187 if (on) {
188 ci_role_stop(ci);
189 ci_role_start(ci, CI_ROLE_HOST);
190 } else {
191 ci_role_stop(ci);
192 hw_device_reset(ci, USBMODE_CM_DC);
193 ci_role_start(ci, CI_ROLE_GADGET);
194 }
195 mutex_lock(&fsm->lock);
196 return 0;
197}
198
199static int ci_otg_start_gadget(struct otg_fsm *fsm, int on)
200{
201 struct ci_hdrc *ci = container_of(fsm, struct ci_hdrc, fsm);
202
203 mutex_unlock(&fsm->lock);
204 if (on)
205 usb_gadget_vbus_connect(&ci->gadget);
206 else
207 usb_gadget_vbus_disconnect(&ci->gadget);
208 mutex_lock(&fsm->lock);
209
210 return 0;
211}
212
213static struct otg_fsm_ops ci_otg_ops = {
214 .drv_vbus = ci_otg_drv_vbus,
215 .loc_conn = ci_otg_loc_conn,
216 .loc_sof = ci_otg_loc_sof,
217 .start_pulse = ci_otg_start_pulse,
218 .add_timer = ci_otg_fsm_add_timer,
219 .del_timer = ci_otg_fsm_del_timer,
220 .start_host = ci_otg_start_host,
221 .start_gadget = ci_otg_start_gadget,
222};
223
28int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) 224int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
29{ 225{
30 struct usb_otg *otg; 226 struct usb_otg *otg;
@@ -46,6 +242,7 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
46 ci->fsm.power_up = 1; 242 ci->fsm.power_up = 1;
47 ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; 243 ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
48 ci->transceiver->state = OTG_STATE_UNDEFINED; 244 ci->transceiver->state = OTG_STATE_UNDEFINED;
245 ci->fsm.ops = &ci_otg_ops;
49 246
50 mutex_init(&ci->fsm.lock); 247 mutex_init(&ci->fsm.lock);
51 248
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h
index bf20a851b601..4d0dfe6900d6 100644
--- a/drivers/usb/chipidea/otg_fsm.h
+++ b/drivers/usb/chipidea/otg_fsm.h
@@ -13,6 +13,31 @@
13 13
14#include <linux/usb/otg-fsm.h> 14#include <linux/usb/otg-fsm.h>
15 15
16enum ci_otg_fsm_timer_index {
17 /*
18 * CI specific timers, start from the end
19 * of standard and auxiliary OTG timers
20 */
21 B_DATA_PLS = NUM_OTG_FSM_TIMERS,
22 B_SSEND_SRP,
23 B_SESS_VLD,
24
25 NUM_CI_OTG_FSM_TIMERS,
26};
27
28struct ci_otg_fsm_timer {
29 unsigned long expires; /* Number of count increase to timeout */
30 unsigned long count; /* Tick counter */
31 void (*function)(void *, unsigned long); /* Timeout function */
32 unsigned long data; /* Data passed to function */
33 struct list_head list;
34};
35
36struct ci_otg_fsm_timer_list {
37 struct ci_otg_fsm_timer *timer_list[NUM_CI_OTG_FSM_TIMERS];
38 struct list_head active_timers;
39};
40
16#ifdef CONFIG_USB_OTG_FSM 41#ifdef CONFIG_USB_OTG_FSM
17 42
18int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci); 43int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci);