Merge branch 'for-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[cascardo/linux.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 waking up HW device from Idle mode.
7                                                 A software abort pattern is written to the device to wake it and necessary power state
8                                                 transitions from host are performed here.
9
10 Input parameters:               IN struct bcm_mini_adapter *Adapter   - Miniport Adapter Context
11
12
13 Return:                         BCM_STATUS_SUCCESS - If Wakeup of the HW Interface was successful.
14                                                 Other           - If an error occurred.
15 */
16
17
18 /*
19 Function:                               InterfaceIdleModeRespond
20
21 Description:                    This is the hardware specific Function for responding to Idle mode request from target.
22                                                 Necessary power state transitions from host for idle mode or other device specific
23                                                 initializations are performed here.
24
25 Input parameters:               IN struct bcm_mini_adapter * Adapter   - Miniport Adapter Context
26
27
28 Return:                         BCM_STATUS_SUCCESS - If Idle mode response related HW configuration was successful.
29                                                 Other           - If an error occurred.
30 */
31
32 /*
33 "dmem bfc02f00  100" tells how many time device went in Idle mode.
34 this value will be at address bfc02fa4.just before value d0ea1dle.
35
36 Set time value by writing at bfc02f98 7d0
37
38 checking the Ack timer expire on kannon by running command
39 d qcslog .. if it shows e means host has not send response to f/w with in 200 ms. Response should be
40 send to f/w with in 200 ms after the Idle/Shutdown req issued
41
42 */
43
44
45 int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, unsigned int *puiBuffer)
46 {
47         int     status = STATUS_SUCCESS;
48         unsigned int    uiRegRead = 0;
49         int bytes;
50
51         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "SubType of Message :0x%X", ntohl(*puiBuffer));
52
53         if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) {
54                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, " Got GO_TO_IDLE_MODE_PAYLOAD(210) Msg Subtype");
55                 if (ntohl(*(puiBuffer+1)) == 0 ) {
56                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Got IDLE MODE WAKE UP Response From F/W");
57
58                         status = wrmalt (Adapter, SW_ABORT_IDLEMODE_LOC, &uiRegRead, sizeof(uiRegRead));
59                         if (status) {
60                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg");
61                                 return status;
62                         }
63
64                         if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
65                                 uiRegRead = 0x00000000 ;
66                                 status = wrmalt (Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegRead, sizeof(uiRegRead));
67                                 if (status) {
68                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode    Reg");
69                                         return status;
70                                 }
71                         }
72                         /* Below Register should not br read in case of Manual and Protocol Idle mode */
73                         else if (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) {
74                                 /* clear on read Register */
75                                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegRead, sizeof(uiRegRead));
76                                 if (bytes < 0) {
77                                         status = bytes;
78                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort Reg0");
79                                         return status;
80                                 }
81                                 /* clear on read Register */
82                                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegRead, sizeof(uiRegRead));
83                                 if (bytes < 0) {
84                                         status = bytes;
85                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed while clearing H/W Abort    Reg1");
86                                         return status;
87                                 }
88                         }
89                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Device Up from Idle Mode");
90
91                         /* Set Idle Mode Flag to False and Clear IdleMode reg. */
92                         Adapter->IdleMode = false;
93                         Adapter->bTriedToWakeUpFromlowPowerMode = false;
94
95                         wake_up(&Adapter->lowpower_mode_wait_queue);
96
97                 } else {
98                         if (TRUE == Adapter->IdleMode)
99                         {
100                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Device is already in Idle mode....");
101                                 return status ;
102                         }
103
104                         uiRegRead = 0;
105                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Got Req from F/W to go in IDLE mode \n");
106
107                         if (Adapter->chip_id == BCS220_2 ||
108                                 Adapter->chip_id == BCS220_2BC ||
109                                         Adapter->chip_id == BCS250_BC ||
110                                         Adapter->chip_id == BCS220_3) {
111
112                                 bytes = rdmalt(Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead));
113                                 if (bytes < 0) {
114                                         status = bytes;
115                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "rdm failed while Reading HPM_CONFIG_LDO145 Reg 0\n");
116                                         return status;
117                                 }
118
119
120                                 uiRegRead |= (1<<17);
121
122                                 status = wrmalt (Adapter, HPM_CONFIG_MSW, &uiRegRead, sizeof(uiRegRead));
123                                 if (status) {
124                                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed while clearing Idle Mode Reg\n");
125                                         return status;
126                                 }
127
128                         }
129                         SendIdleModeResponse(Adapter);
130                 }
131         } else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) {
132                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "OverRiding Service Flow Params");
133                 OverrideServiceFlowParams(Adapter, puiBuffer);
134         }
135         return status;
136 }
137
138 static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter, unsigned int Pattern)
139 {
140         int     status = STATUS_SUCCESS;
141         unsigned int value;
142         unsigned int chip_id ;
143         unsigned long timeout = 0, itr = 0;
144
145         int     lenwritten = 0;
146         unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
147         struct bcm_interface_adapter *psInterfaceAdapter = Adapter->pvInterfaceAdapter;
148
149         /* Abort Bus suspend if its already suspended */
150         if ((TRUE == psInterfaceAdapter->bSuspended) && (TRUE == Adapter->bDoSuspend)) {
151                 status = usb_autopm_get_interface(psInterfaceAdapter->interface);
152                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Bus got wakeup..Aborting Idle mode... status:%d \n", status);
153
154         }
155
156         if ((Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING)
157                                                                         ||
158            (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) {
159                 /* write the SW abort pattern. */
160                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Writing pattern<%d> to SW_ABORT_IDLEMODE_LOC\n", Pattern);
161                 status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(Pattern));
162                 if (status) {
163                                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "WRM to Register SW_ABORT_IDLEMODE_LOC failed..");
164                                 return status;
165                 }
166         }
167
168         if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
169                 value = 0x80000000;
170                 status = wrmalt(Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &value, sizeof(value));
171                 if (status)
172                 {
173                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Register failed");
174                         return status;
175                 }
176         } else if (Adapter->ulPowerSaveMode != 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                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Sending Abort pattern down fails with status:%d..\n", status);
191                         return status;
192                 } else {
193                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "NOB Sent down :%d", lenwritten);
194                 }
195
196                 /* mdelay(25); */
197
198                 timeout = jiffies +  msecs_to_jiffies(50) ;
199                 while ( 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 (timeout < jiffies )
208                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Not able to read chip-id even after 25 msec");
209                 else
210                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Number of completed iteration to read chip-id :%lu", itr);
211
212                 status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, &Pattern, sizeof(status));
213                 if (status) {
214                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM to Register SW_ABORT_IDLEMODE_LOC failed..");
215                         return status;
216                 }
217         }
218         return status;
219 }
220 int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter)
221 {
222         ULONG   Status = 0;
223         if (Adapter->bTriedToWakeUpFromlowPowerMode) {
224                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Wake up already attempted.. ignoring\n");
225         } else {
226                 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, IDLE_MODE, DBG_LVL_ALL, "Writing Low Power Mode Abort pattern to the Device\n");
227                 Adapter->bTriedToWakeUpFromlowPowerMode = TRUE;
228                 InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern);
229
230         }
231         return Status;
232 }
233
234 void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter)
235 {
236         unsigned int uiRegVal = 0;
237         INT Status = 0;
238         int bytes;
239
240         if (Adapter->ulPowerSaveMode == DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) {
241                 /* clear idlemode interrupt. */
242                 uiRegVal = 0;
243                 Status = wrmalt(Adapter, DEBUG_INTERRUPT_GENERATOR_REGISTOR, &uiRegVal, sizeof(uiRegVal));
244                 if (Status) {
245                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0,"WRM to DEBUG_INTERRUPT_GENERATOR_REGISTOR Failed with err :%d", Status);
246                         return;
247                 }
248         }
249
250     else {
251
252         /* clear Interrupt EP registers. */
253                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, &uiRegVal, sizeof(uiRegVal));
254                 if (bytes < 0) {
255                         Status = bytes;
256                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM of DEVICE_INT_OUT_EP_REG0 failed with Err :%d", Status);
257                         return;
258                 }
259
260                 bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, &uiRegVal, sizeof(uiRegVal));
261                 if (bytes < 0) {
262                         Status = bytes;
263                         BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "RDM of DEVICE_INT_OUT_EP_REG1 failed with Err :%d", Status);
264                         return;
265                 }
266         }
267 }
268