Linux-libre 3.16.85-gnu
[librecmc/linux-libre.git] / drivers / staging / bcm / InterfaceIdleMode.c
1 #include "headers.h"
2
3 /*
4 Function:       InterfaceIdleModeWakeup
5
6 Description:    This is the hardware specific Function for
7                 waking up HW device from Idle mode.
8                 A software abort pattern is written to the
9                 device to wake it and necessary power state
10                 transitions from host are performed here.
11
12 Input parameters: IN struct bcm_mini_adapter *Adapter
13                   - Miniport Adapter Context
14
15 Return:         BCM_STATUS_SUCCESS - If Wakeup of the HW Interface
16                                      was successful.
17                 Other              - If an error occurred.
18 */
19
20 /*
21 Function:       InterfaceIdleModeRespond
22
23 Description:    This is the hardware specific Function for
24                 responding to Idle mode request from target.
25                 Necessary power state transitions from host for
26                 idle mode or other device specific initializations
27                 are performed here.
28
29 Input parameters: IN struct bcm_mini_adapter * Adapter
30                   - Miniport Adapter Context
31
32 Return:         BCM_STATUS_SUCCESS - If Idle mode response related
33                                      HW configuration was successful.
34                 Other              - If an error occurred.
35 */
36
37 /*
38 "dmem bfc02f00  100" tells how many time device went in Idle mode.
39 this value will be at address bfc02fa4.just before value d0ea1dle.
40
41 Set time value by writing at bfc02f98 7d0
42
43 checking the Ack timer expire on kannon by running command
44 d qcslog .. if it shows e means host has not send response
45 to f/w with in 200 ms. Response should be
46 send to f/w with in 200 ms after the Idle/Shutdown req issued
47
48 */
49
50
51 int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter,
52                         unsigned int *puiBuffer)
53 {
54         int     status = STATUS_SUCCESS;
55         unsigned int    uiRegRead = 0;
56         int bytes;
57
58         if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) {
59                 if (ntohl(*(puiBuffer+1)) == 0) {
60
61                         status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
62                                         &uiRegRead, sizeof(uiRegRead));
63                         if (status)
64                                 return status;
65
66                         if (Adapter->ulPowerSaveMode ==
67                                 DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
68                                 uiRegRead = 0x00000000;
69                                 status = wrmalt(Adapter,
70                                         DEBUG_INTERRUPT_GENERATOR_REGISTOR,
71                                         &uiRegRead, sizeof(uiRegRead));
72                                 if (status)
73                                         return status;
74                         }
75                         /* Below Register should not br read in case of
76                          * Manual and Protocol Idle mode */
77                         else if (Adapter->ulPowerSaveMode !=
78                                 DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
79                                 /* clear on read Register */
80                                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0,
81                                         &uiRegRead, sizeof(uiRegRead));
82                                 if (bytes < 0) {
83                                         status = bytes;
84                                         return status;
85                                 }
86                                 /* clear on read Register */
87                                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1,
88                                         &uiRegRead, sizeof(uiRegRead));
89                                 if (bytes < 0) {
90                                         status = bytes;
91                                         return status;
92                                 }
93                         }
94
95                         /* Set Idle Mode Flag to False and
96                          * Clear IdleMode reg. */
97                         Adapter->IdleMode = false;
98                         Adapter->bTriedToWakeUpFromlowPowerMode = false;
99
100                         wake_up(&Adapter->lowpower_mode_wait_queue);
101
102                 } else {
103                         if (TRUE == Adapter->IdleMode)
104                                 return status;
105
106                         uiRegRead = 0;
107
108                         if (Adapter->chip_id == BCS220_2 ||
109                                 Adapter->chip_id == BCS220_2BC ||
110                                         Adapter->chip_id == BCS250_BC ||
111                                         Adapter->chip_id == BCS220_3) {
112
113                                 bytes = rdmalt(Adapter, HPM_CONFIG_MSW,
114                                         &uiRegRead, sizeof(uiRegRead));
115                                 if (bytes < 0) {
116                                         status = bytes;
117                                         return status;
118                                 }
119
120
121                                 uiRegRead |= (1<<17);
122
123                                 status = wrmalt(Adapter, HPM_CONFIG_MSW,
124                                         &uiRegRead, sizeof(uiRegRead));
125                                 if (status)
126                                         return status;
127                         }
128                         SendIdleModeResponse(Adapter);
129                 }
130         } else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) {
131                 OverrideServiceFlowParams(Adapter, puiBuffer);
132         }
133         return status;
134 }
135
136 static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter,
137                                 unsigned int Pattern)
138 {
139         int status = STATUS_SUCCESS;
140         unsigned int value;
141         unsigned int chip_id;
142         unsigned long timeout = 0, itr = 0;
143
144         int lenwritten = 0;
145         unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
146                                                 0xFF, 0xFF, 0xFF};
147         struct bcm_interface_adapter *psInterfaceAdapter =
148                                 Adapter->pvInterfaceAdapter;
149
150         /* Abort Bus suspend if its already suspended */
151         if ((TRUE == psInterfaceAdapter->bSuspended) &&
152                         (TRUE == Adapter->bDoSuspend))
153                 status = usb_autopm_get_interface(
154                                 psInterfaceAdapter->interface);
155
156         if ((Adapter->ulPowerSaveMode ==
157                         DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) ||
158            (Adapter->ulPowerSaveMode ==
159                         DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) {
160                 /* write the SW abort pattern. */
161                 status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
162                                 &Pattern, sizeof(Pattern));
163                 if (status)
164                         return status;
165         }
166
167         if (Adapter->ulPowerSaveMode ==
168                 DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
169                 value = 0x80000000;
170                 status = wrmalt(Adapter,
171                                 DEBUG_INTERRUPT_GENERATOR_REGISTOR,
172                                 &value, sizeof(value));
173                 if (status)
174                         return status;
175         } else if (Adapter->ulPowerSaveMode !=
176                         DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
177                 /*
178                  * Get a Interrupt Out URB and send 8 Bytes Down
179                  * To be Done in Thread Context.
180                  * Not using Asynchronous Mechanism.
181                  */
182                 status = usb_interrupt_msg(psInterfaceAdapter->udev,
183                         usb_sndintpipe(psInterfaceAdapter->udev,
184                         psInterfaceAdapter->sIntrOut.int_out_endpointAddr),
185                         aucAbortPattern,
186                         8,
187                         &lenwritten,
188                         5000);
189                 if (status)
190                         return status;
191                 else
192                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
193                                 IDLE_MODE, DBG_LVL_ALL,
194                                 "NOB Sent down :%d", lenwritten);
195
196                 /* mdelay(25); */
197
198                 timeout = jiffies +  msecs_to_jiffies(50);
199                 while (time_after(timeout, jiffies)) {
200                         itr++;
201                         rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT));
202                         if (0xbece3200 == (chip_id&~(0xF0)))
203                                 chip_id = chip_id&~(0xF0);
204                         if (chip_id == Adapter->chip_id)
205                                 break;
206                 }
207                 if (time_before(timeout, jiffies))
208                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
209                                 IDLE_MODE, DBG_LVL_ALL,
210                                 "Not able to read chip-id even after 25 msec");
211                 else
212                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
213                                 IDLE_MODE, DBG_LVL_ALL,
214                                 "Number of completed iteration to"
215                                 "read chip-id :%lu", itr);
216
217                 status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC,
218                                 &Pattern, sizeof(status));
219                 if (status)
220                         return status;
221         }
222         return status;
223 }
224 int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
225 {
226         if (Adapter->bTriedToWakeUpFromlowPowerMode) {
227                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS,
228                 IDLE_MODE, DBG_LVL_ALL,
229                 "Wake up already attempted.. ignoring\n");
230         } else {
231                 Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
232                 InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern);
233
234         }
235         return 0;
236 }
237
238 void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
239 {
240         unsigned int uiRegVal = 0;
241         INT Status = 0;
242         int bytes;
243
244         if (Adapter->ulPowerSaveMode ==
245                 DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
246                 /* clear idlemode interrupt. */
247                 uiRegVal = 0;
248                 Status = wrmalt(Adapter,
249                         DEBUG_INTERRUPT_GENERATOR_REGISTOR,
250                         &uiRegVal, sizeof(uiRegVal));
251                 if (Status)
252                         return;
253         }
254
255         else {
256
257 /* clear Interrupt EP registers. */
258                 bytes = rdmalt(Adapter,
259                         DEVICE_INT_OUT_EP_REG0,
260                         &uiRegVal, sizeof(uiRegVal));
261                 if (bytes < 0) {
262                         Status = bytes;
263                         return;
264                 }
265
266                 bytes = rdmalt(Adapter,
267                         DEVICE_INT_OUT_EP_REG1,
268                         &uiRegVal, sizeof(uiRegVal));
269                 if (bytes < 0) {
270                         Status = bytes;
271                         return;
272                 }
273         }
274 }
275