Linux-libre 3.0.78-gnu1
[librecmc/linux-libre.git] / drivers / staging / westbridge / astoria / api / src / cyasmisc.c
1 /* Cypress West Bridge API source file (cyasmisc.c)
2 ## ===========================
3 ## Copyright (C) 2010  Cypress Semiconductor
4 ##
5 ## This program is free software; you can redistribute it and/or
6 ## modify it under the terms of the GNU General Public License
7 ## as published by the Free Software Foundation; either version 2
8 ## of the License, or (at your option) any later version.
9 ##
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ## GNU General Public License for more details.
14 ##
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; if not, write to the Free Software
17 ## Foundation, Inc., 51 Franklin Street, Fifth Floor
18 ## Boston, MA  02110-1301, USA.
19 ## ===========================
20 */
21
22 #include "../../include/linux/westbridge/cyashal.h"
23 #include "../../include/linux/westbridge/cyasmisc.h"
24 #include "../../include/linux/westbridge/cyasdma.h"
25 #include "../../include/linux/westbridge/cyasintr.h"
26 #include "../../include/linux/westbridge/cyaserr.h"
27 #include "../../include/linux/westbridge/cyasregs.h"
28 #include "../../include/linux/westbridge/cyaslowlevel.h"
29 #include "../../include/linux/westbridge/cyasprotocol.h"
30
31 /*
32 * The device list, the only global in the API
33 */
34 static cy_as_device *g_device_list;
35
36 /*
37  * The current debug level
38  */
39 static uint8_t debug_level;
40
41 /*
42  * This function sets the debug level for the API
43  *
44  */
45 void
46 cy_as_misc_set_log_level(uint8_t level)
47 {
48         debug_level = level;
49 }
50
51 #ifdef CY_AS_LOG_SUPPORT
52
53 /*
54  * This function is a low level logger for the API.
55  */
56 void
57 cy_as_log_debug_message(int level, const char *str)
58 {
59         if (level <= debug_level)
60                 cy_as_hal_print_message("log %d: %s\n", level, str);
61 }
62
63 #endif
64
65 #define cy_as_check_device_ready(dev_p)                 \
66 {\
67         if (!(dev_p) || ((dev_p)->sig !=                        \
68                 CY_AS_DEVICE_HANDLE_SIGNATURE))                 \
69                 return CY_AS_ERROR_INVALID_HANDLE;              \
70 \
71         if (!cy_as_device_is_configured(dev_p))         \
72                 return CY_AS_ERROR_NOT_CONFIGURED;              \
73 \
74         if (!cy_as_device_is_firmware_loaded(dev_p))\
75                 return CY_AS_ERROR_NO_FIRMWARE;         \
76 }
77
78 /* Find an West Bridge device based on a TAG */
79 cy_as_device *
80 cy_as_device_find_from_tag(cy_as_hal_device_tag tag)
81 {
82         cy_as_device *dev_p;
83
84         for (dev_p = g_device_list; dev_p != 0; dev_p = dev_p->next_p) {
85                 if (dev_p->tag == tag)
86                         return dev_p;
87         }
88
89         return 0;
90 }
91
92 /* Map a pre-V1.2 media type to the V1.2+ bus number */
93 static void
94 cy_as_bus_from_media_type(cy_as_media_type type,
95                                                 cy_as_bus_number_t *bus)
96 {
97         if (type == cy_as_media_nand)
98                 *bus = 0;
99         else
100                 *bus = 1;
101 }
102
103 static cy_as_return_status_t
104 my_handle_response_no_data(cy_as_device *dev_p,
105                         cy_as_ll_request_response *req_p,
106                         cy_as_ll_request_response *reply_p)
107 {
108         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
109
110         if (cy_as_ll_request_response__get_code(reply_p) !=
111                 CY_RESP_SUCCESS_FAILURE)
112                 ret = CY_AS_ERROR_INVALID_RESPONSE;
113         else
114                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
115
116         cy_as_ll_destroy_request(dev_p, req_p);
117         cy_as_ll_destroy_response(dev_p, reply_p);
118
119         return ret;
120 }
121
122 /*
123 * Create a new West Bridge device
124 */
125 cy_as_return_status_t
126 cy_as_misc_create_device(cy_as_device_handle *handle_p,
127         cy_as_hal_device_tag tag)
128 {
129         cy_as_device *dev_p;
130         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
131
132         cy_as_log_debug_message(6, "cy_as_misc_create_device called");
133
134         dev_p = (cy_as_device *)cy_as_hal_alloc(sizeof(cy_as_device));
135         if (dev_p == 0)
136                 return CY_AS_ERROR_OUT_OF_MEMORY;
137         cy_as_hal_mem_set(dev_p, 0, sizeof(cy_as_device));
138
139         /*
140          * dynamically allocating this buffer to ensure that it is
141          * word aligned.
142          */
143         dev_p->usb_ep_data = (uint8_t *)cy_as_hal_alloc(64 * sizeof(uint8_t));
144         if (dev_p->usb_ep_data == 0) {
145                 cy_as_hal_free(dev_p);
146                 return CY_AS_ERROR_OUT_OF_MEMORY;
147         }
148
149         dev_p->sig = CY_AS_DEVICE_HANDLE_SIGNATURE;
150         dev_p->tag = tag;
151         dev_p->usb_max_tx_size = 0x40;
152
153         dev_p->storage_write_endpoint = CY_AS_P2S_WRITE_ENDPOINT;
154         dev_p->storage_read_endpoint = CY_AS_P2S_READ_ENDPOINT;
155
156         dev_p->func_cbs_misc = cy_as_create_c_b_queue(CYAS_FUNC_CB);
157         if (dev_p->func_cbs_misc == 0)
158                 goto destroy;
159
160         dev_p->func_cbs_res = cy_as_create_c_b_queue(CYAS_FUNC_CB);
161         if (dev_p->func_cbs_res == 0)
162                 goto destroy;
163
164         dev_p->func_cbs_stor = cy_as_create_c_b_queue(CYAS_FUNC_CB);
165         if (dev_p->func_cbs_stor == 0)
166                 goto destroy;
167
168         dev_p->func_cbs_usb = cy_as_create_c_b_queue(CYAS_FUNC_CB);
169         if (dev_p->func_cbs_usb == 0)
170                 goto destroy;
171
172         dev_p->func_cbs_mtp = cy_as_create_c_b_queue(CYAS_FUNC_CB);
173         if (dev_p->func_cbs_mtp == 0)
174                         goto destroy;
175
176         /*
177          * allocate memory for the DMA module here. it is then marked idle, and
178          * will be activated when cy_as_misc_configure_device is called.
179          */
180         ret = cy_as_dma_start(dev_p);
181         if (ret != CY_AS_ERROR_SUCCESS)
182                 goto destroy;
183
184         cy_as_device_set_dma_stopped(dev_p);
185
186         /*
187          * allocate memory for the low level module here. this module is also
188          * activated only when cy_as_misc_configure_device is called.
189          */
190         ret = cy_as_ll_start(dev_p);
191         if (ret != CY_AS_ERROR_SUCCESS)
192                 goto destroy;
193
194         cy_as_device_set_low_level_stopped(dev_p);
195
196         dev_p->next_p = g_device_list;
197         g_device_list = dev_p;
198
199         *handle_p = dev_p;
200         cy_as_hal_init_dev_registers(tag, cy_false);
201         return CY_AS_ERROR_SUCCESS;
202
203 destroy:
204         /* Free any queues that were successfully allocated. */
205         if (dev_p->func_cbs_misc)
206                 cy_as_destroy_c_b_queue(dev_p->func_cbs_misc);
207
208         if (dev_p->func_cbs_res)
209                 cy_as_destroy_c_b_queue(dev_p->func_cbs_res);
210
211         if (dev_p->func_cbs_stor)
212                 cy_as_destroy_c_b_queue(dev_p->func_cbs_stor);
213
214         if (dev_p->func_cbs_usb)
215                 cy_as_destroy_c_b_queue(dev_p->func_cbs_usb);
216
217         if (dev_p->func_cbs_mtp)
218                 cy_as_destroy_c_b_queue(dev_p->func_cbs_mtp);
219
220         cy_as_hal_free(dev_p->usb_ep_data);
221         cy_as_hal_free(dev_p);
222
223         if (ret != CY_AS_ERROR_SUCCESS)
224                 return ret;
225         else
226                 return CY_AS_ERROR_OUT_OF_MEMORY;
227 }
228
229 /*
230 * Destroy an existing West Bridge device
231 */
232 cy_as_return_status_t
233 cy_as_misc_destroy_device(cy_as_device_handle handle)
234 {
235         cy_as_return_status_t ret;
236         cy_as_device *dev_p;
237
238         cy_as_log_debug_message(6, "cy_as_misc_destroy_device called");
239
240         dev_p = (cy_as_device *)handle;
241         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
242                 return CY_AS_ERROR_INVALID_HANDLE;
243
244         /*
245         * if the USB stack is still running,
246         * it must be stopped first
247         */
248         if (dev_p->usb_count > 0)
249                 return CY_AS_ERROR_STILL_RUNNING;
250
251         /*
252         * if the STORAGE stack is still running,
253         * it must be stopped first
254         */
255         if (dev_p->storage_count > 0)
256                 return CY_AS_ERROR_STILL_RUNNING;
257
258         if (cy_as_device_is_intr_running(dev_p))
259                 ret = cy_as_intr_stop(dev_p);
260
261         ret = cy_as_ll_stop(dev_p);
262         if (ret != CY_AS_ERROR_SUCCESS) {
263                 cy_as_intr_start(dev_p, dev_p->use_int_drq);
264                 return ret;
265         }
266
267         ret = cy_as_dma_stop(dev_p);
268         if (ret != CY_AS_ERROR_SUCCESS) {
269                 cy_as_intr_start(dev_p, dev_p->use_int_drq);
270                 return ret;
271         }
272
273         /* Reset the West Bridge device. */
274         cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_RST_CTRL_REG,
275                 CY_AS_MEM_RST_CTRL_REG_HARD);
276
277         /*
278         * remove the device from the device list
279         */
280         if (g_device_list == dev_p) {
281                 g_device_list = dev_p->next_p;
282         } else {
283                 cy_as_device *tmp_p = g_device_list;
284                 while (tmp_p && tmp_p->next_p != dev_p)
285                         tmp_p = tmp_p->next_p;
286
287                 cy_as_hal_assert(tmp_p != 0);
288                 tmp_p->next_p = dev_p->next_p;
289         }
290
291         /*
292         * reset the signature so this will not be detected
293         * as a valid handle
294         */
295         dev_p->sig = 0;
296
297         cy_as_destroy_c_b_queue(dev_p->func_cbs_misc);
298         cy_as_destroy_c_b_queue(dev_p->func_cbs_res);
299         cy_as_destroy_c_b_queue(dev_p->func_cbs_stor);
300         cy_as_destroy_c_b_queue(dev_p->func_cbs_usb);
301         cy_as_destroy_c_b_queue(dev_p->func_cbs_mtp);
302
303         /*
304         * free the memory associated with the device
305         */
306         cy_as_hal_free(dev_p->usb_ep_data);
307         cy_as_hal_free(dev_p);
308
309         return CY_AS_ERROR_SUCCESS;
310 }
311
312 /*
313 * Determine the endian mode for the processor we are
314 * running on, then set the endian mode register
315 */
316 static void
317 cy_as_setup_endian_mode(cy_as_device *dev_p)
318 {
319         /*
320         * In general, we always set west bridge intothe little
321         * endian mode. this causes the data on bit 0 internally
322         * to come out on data line 0 externally and it is generally
323         * what we want regardless of the endian mode of the
324         * processor.  this capability in west bridge should be
325         * labeled as a "SWAP" capability and can be used to swap the
326         * bytes of data in and out of west bridge.  this is
327         * useful if there is DMA hardware that requires this for some
328         * reason I cannot imagine at this time.  basically if the
329         * wires are connected correctly, we should never need to
330         * change the endian-ness of west bridge.
331         */
332         cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_ENDIAN,
333                 CY_AS_LITTLE_ENDIAN);
334 }
335
336 /*
337 * Query the West Bridge device and determine if we are an standby mode
338 */
339 cy_as_return_status_t
340 cy_as_misc_in_standby(cy_as_device_handle handle, cy_bool *standby)
341 {
342         cy_as_device *dev_p;
343
344         cy_as_log_debug_message(6, "cy_as_misc_in_standby called");
345
346         dev_p = (cy_as_device *)handle;
347         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
348                 return CY_AS_ERROR_INVALID_HANDLE;
349
350         if (cy_as_device_is_pin_standby(dev_p) ||
351                 cy_as_device_is_register_standby(dev_p)) {
352                 *standby = cy_true;
353         } else
354                 *standby = cy_false;
355
356         return CY_AS_ERROR_SUCCESS;
357 }
358
359 static void
360 cy_as_misc_func_callback(cy_as_device *dev_p,
361                                                 uint8_t context,
362                                                 cy_as_ll_request_response *rqt,
363                                                 cy_as_ll_request_response *resp,
364                                                 cy_as_return_status_t ret);
365
366
367 static void
368 my_misc_callback(cy_as_device *dev_p, uint8_t context,
369                 cy_as_ll_request_response *req_p,
370                 cy_as_ll_request_response *resp_p,
371                 cy_as_return_status_t ret)
372 {
373         (void)resp_p;
374         (void)context;
375         (void)ret;
376
377         switch (cy_as_ll_request_response__get_code(req_p)) {
378         case CY_RQT_INITIALIZATION_COMPLETE:
379                 {
380                         uint16_t v;
381
382                         cy_as_ll_send_status_response(dev_p,
383                                 CY_RQT_GENERAL_RQT_CONTEXT,
384                                 CY_AS_ERROR_SUCCESS, 0);
385                         cy_as_device_set_firmware_loaded(dev_p);
386
387                         if (cy_as_device_is_waking(dev_p)) {
388                                 /*
389                                  * this is a callback from a
390                                  * cy_as_misc_leave_standby()
391                                  * request. in this case we call
392                                  * the standby callback and clear
393                                  * the waking state.
394                                  */
395                                 if (dev_p->misc_event_cb)
396                                         dev_p->misc_event_cb(
397                                          (cy_as_device_handle)dev_p,
398                                          cy_as_event_misc_awake, 0);
399                                 cy_as_device_clear_waking(dev_p);
400                         } else {
401                                 v = cy_as_ll_request_response__get_word
402                                         (req_p, 3);
403
404                                 /*
405                                  * store the media supported on
406                                  * each of the device buses.
407                                  */
408                                 dev_p->media_supported[0] =
409                                         (uint8_t)(v & 0xFF);
410                                 dev_p->media_supported[1] =
411                                         (uint8_t)((v >> 8) & 0xFF);
412
413                                 v = cy_as_ll_request_response__get_word
414                                         (req_p, 4);
415
416                                 dev_p->is_mtp_firmware  =
417                                         (cy_bool)((v >> 8) & 0xFF);
418
419                                 if (dev_p->misc_event_cb)
420                                         dev_p->misc_event_cb(
421                                          (cy_as_device_handle)dev_p,
422                                          cy_as_event_misc_initialized, 0);
423                         }
424
425                         v = cy_as_hal_read_register(dev_p->tag,
426                                 CY_AS_MEM_P0_VM_SET);
427
428                                 if (v & CY_AS_MEM_P0_VM_SET_CFGMODE)
429                                         cy_as_hal_print_message(
430                                         "initialization message "
431                                         "received, but config bit "
432                                         "still set\n");
433
434                                 v = cy_as_hal_read_register(dev_p->tag,
435                                         CY_AS_MEM_RST_CTRL_REG);
436                                 if ((v & CY_AS_MEM_RST_RSTCMPT) == 0)
437                                         cy_as_hal_print_message(
438                                         "initialization message "
439                                         "received, but reset complete "
440                                         "bit still not set\n");
441                         }
442                         break;
443
444         case CY_RQT_OUT_OF_SUSPEND:
445                 cy_as_ll_send_status_response(dev_p, CY_RQT_GENERAL_RQT_CONTEXT,
446                         CY_AS_ERROR_SUCCESS, 0);
447                         cy_as_device_clear_suspend_mode(dev_p);
448
449                 /*
450                  * if the wakeup was caused by an async cy_as_misc_leave_suspend
451                  * call, we have to call the corresponding callback.
452                  */
453                 if (dev_p->func_cbs_misc->count > 0) {
454                         cy_as_func_c_b_node *node = (cy_as_func_c_b_node *)
455                                         dev_p->func_cbs_misc->head_p;
456                         cy_as_hal_assert(node);
457
458                         if (cy_as_funct_c_b_type_get_type(node->data_type) ==
459                                 CY_FUNCT_CB_MISC_LEAVESUSPEND) {
460                                 cy_as_hal_assert(node->cb_p != 0);
461
462                                 node->cb_p((cy_as_device_handle)dev_p,
463                                         CY_AS_ERROR_SUCCESS, node->client_data,
464                                         CY_FUNCT_CB_MISC_LEAVESUSPEND, 0);
465                                 cy_as_remove_c_b_node(dev_p->func_cbs_misc);
466                         }
467                 }
468
469                 if (dev_p->misc_event_cb)
470                         dev_p->misc_event_cb((cy_as_device_handle)dev_p,
471                                 cy_as_event_misc_wakeup, 0);
472                         break;
473
474         case CY_RQT_DEBUG_MESSAGE:
475                 if ((req_p->data[0] == 0) && (req_p->data[1] == 0) &&
476                         (req_p->data[2] == 0)) {
477                         if (dev_p->misc_event_cb)
478                                 dev_p->misc_event_cb((cy_as_device_handle)dev_p,
479                                         cy_as_event_misc_heart_beat, 0);
480                 } else {
481                         cy_as_hal_print_message(
482                                 "**** debug message: %02x "
483                                 "%02x %02x %02x %02x %02x\n",
484                                 req_p->data[0] & 0xff,
485                                 (req_p->data[0] >> 8) & 0xff,
486                                 req_p->data[1] & 0xff,
487                                 (req_p->data[1] >> 8) & 0xff,
488                                 req_p->data[2] & 0xff,
489                                 (req_p->data[2] >> 8) & 0xff);
490                 }
491                 break;
492
493         case CY_RQT_WB_DEVICE_MISMATCH:
494                 {
495                         if (dev_p->misc_event_cb)
496                                 dev_p->misc_event_cb((cy_as_device_handle)dev_p,
497                                         cy_as_event_misc_device_mismatch, 0);
498                 }
499                 break;
500
501         case CY_RQT_BOOTLOAD_NO_FIRMWARE:
502                 {
503                         /* TODO Handle case when firmware is
504                          * not found during bootloading. */
505                         cy_as_hal_print_message("no firmware image found "
506                         "during bootload. device not started\n");
507                 }
508                 break;
509
510         default:
511                 cy_as_hal_assert(0);
512         }
513 }
514
515 static cy_bool
516 is_valid_silicon_id(uint16_t v)
517 {
518         cy_bool idok = cy_false;
519
520         /*
521         * remove the revision number from the ID value
522         */
523         v = v & CY_AS_MEM_CM_WB_CFG_ID_HDID_MASK;
524
525         /*
526         * if this is west bridge, then we are OK.
527         */
528         if (v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ANTIOCH_VALUE ||
529                 v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ASTORIA_FPGA_VALUE ||
530                 v == CY_AS_MEM_CM_WB_CFG_ID_HDID_ASTORIA_VALUE)
531                 idok = cy_true;
532
533         return idok;
534 }
535
536 /*
537 * Configure the West Bridge device hardware
538 */
539 cy_as_return_status_t
540 cy_as_misc_configure_device(cy_as_device_handle handle,
541         cy_as_device_config *config_p)
542 {
543         cy_as_return_status_t ret;
544         cy_bool standby;
545         cy_as_device *dev_p;
546         uint16_t v;
547         uint16_t fw_present;
548         cy_as_log_debug_message(6, "cy_as_misc_configure_device called");
549
550         dev_p = (cy_as_device *)handle;
551         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
552                 return CY_AS_ERROR_INVALID_HANDLE;
553
554         /* Setup big endian vs little endian */
555         cy_as_setup_endian_mode(dev_p);
556
557         /* Now, confirm that we can talk to the West Bridge device */
558         dev_p->silicon_id = cy_as_hal_read_register(dev_p->tag,
559                 CY_AS_MEM_CM_WB_CFG_ID);
560         fw_present = cy_as_hal_read_register(dev_p->tag,
561                 CY_AS_MEM_RST_CTRL_REG);
562         if (!(fw_present & CY_AS_MEM_RST_RSTCMPT)) {
563                 if (!is_valid_silicon_id(dev_p->silicon_id))
564                         return CY_AS_ERROR_NO_ANTIOCH;
565         }
566         /* Check for standby mode */
567         ret = cy_as_misc_in_standby(handle, &standby);
568         if (ret != CY_AS_ERROR_SUCCESS)
569                 return ret;
570         if (ret)
571                 return CY_AS_ERROR_IN_STANDBY;
572
573         /* Setup P-port interface mode (CRAM / SRAM). */
574         if (cy_as_device_is_astoria_dev(dev_p)) {
575                 if (config_p->srammode)
576                         v = CY_AS_MEM_P0_VM_SET_VMTYPE_SRAM;
577                 else
578                         v = CY_AS_MEM_P0_VM_SET_VMTYPE_RAM;
579         } else
580                 v = CY_AS_MEM_P0_VM_SET_VMTYPE_RAM;
581
582         /* Setup synchronous versus asynchronous mode */
583         if (config_p->sync)
584                 v |= CY_AS_MEM_P0_VM_SET_IFMODE;
585         if (config_p->dackmode == cy_as_device_dack_ack)
586                 v |= CY_AS_MEM_P0_VM_SET_DACKEOB;
587         if (config_p->drqpol)
588                 v |= CY_AS_MEM_P0_VM_SET_DRQPOL;
589         if (config_p->dackpol)
590                 v |= CY_AS_MEM_P0_VM_SET_DACKPOL;
591         cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_VM_SET, v);
592
593         if (config_p->crystal)
594                 cy_as_device_set_crystal(dev_p);
595         else
596                 cy_as_device_set_external_clock(dev_p);
597
598         /* Register a callback to handle MISC requests from the firmware */
599         cy_as_ll_register_request_callback(dev_p,
600                 CY_RQT_GENERAL_RQT_CONTEXT, my_misc_callback);
601
602         /* Now mark the DMA and low level modules as active. */
603         cy_as_device_set_dma_running(dev_p);
604         cy_as_device_set_low_level_running(dev_p);
605
606         /* Now, initialize the interrupt module */
607         dev_p->use_int_drq = config_p->dmaintr;
608         ret = cy_as_intr_start(dev_p, config_p->dmaintr);
609         if (ret != CY_AS_ERROR_SUCCESS)
610                 return ret;
611
612         /* Mark the interface as initialized */
613         cy_as_device_set_configured(dev_p);
614
615         return CY_AS_ERROR_SUCCESS;
616 }
617
618 static void
619 my_dma_callback(cy_as_device *dev_p,
620                           cy_as_end_point_number_t ep,
621                           void *mem_p,
622                           uint32_t                        size,
623                           cy_as_return_status_t ret
624                          )
625 {
626         cy_as_dma_end_point *ep_p;
627
628         (void)size;
629
630         /* Get the endpoint pointer based on the endpoint number */
631         ep_p = CY_AS_NUM_EP(dev_p, ep);
632
633         /* Check the queue to see if is drained */
634         if (ep_p->queue_p == 0) {
635                 cy_as_func_c_b_node *node =
636                         (cy_as_func_c_b_node *)dev_p->func_cbs_misc->head_p;
637
638                 cy_as_hal_assert(node);
639
640                 if (ret == CY_AS_ERROR_SUCCESS) {
641                         /*
642                          * disable endpoint 2.  the storage module
643                          * will enable this EP if necessary.
644                          */
645                         cy_as_dma_enable_end_point(dev_p,
646                                 CY_AS_FIRMWARE_ENDPOINT,
647                                 cy_false, cy_as_direction_in);
648
649                         /*
650                          * clear the reset register.  this releases the
651                          * antioch micro-controller from reset and begins
652                          * running the code at address zero.
653                          */
654                         cy_as_hal_write_register(dev_p->tag,
655                                 CY_AS_MEM_RST_CTRL_REG, 0x00);
656                 }
657
658                 /* Call the user Callback */
659                 node->cb_p((cy_as_device_handle)dev_p, ret, node->client_data,
660                         node->data_type, node->data);
661                 cy_as_remove_c_b_node(dev_p->func_cbs_misc);
662         } else {
663                 /* This is the header data that was allocated in the
664                  * download firmware function, and can be safely freed
665                  * here. */
666                 uint32_t state = cy_as_hal_disable_interrupts();
667                 cy_as_hal_c_b_free(mem_p);
668                 cy_as_hal_enable_interrupts(state);
669         }
670 }
671
672 cy_as_return_status_t
673 cy_as_misc_download_firmware(cy_as_device_handle handle,
674                                                    const void *mem_p,
675                                                    uint16_t size,
676                                                    cy_as_function_callback cb,
677                                                    uint32_t client)
678 {
679         uint8_t *header;
680         cy_as_return_status_t ret;
681         cy_bool standby;
682         cy_as_device *dev_p;
683         cy_as_dma_callback dmacb = 0;
684         uint32_t state;
685
686         cy_as_log_debug_message(6, "cy_as_misc_download_firmware called");
687
688         /* Make sure we have a valid device */
689         dev_p = (cy_as_device *)handle;
690         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
691                 return CY_AS_ERROR_INVALID_HANDLE;
692
693         /*
694         * if the device has not been initialized, we cannot download firmware
695         * to the device.
696         */
697         if (!cy_as_device_is_configured(dev_p))
698                 return CY_AS_ERROR_NOT_CONFIGURED;
699
700         /*
701         * make sure west bridge is not in standby
702         */
703         ret = cy_as_misc_in_standby(dev_p, &standby);
704         if (ret != CY_AS_ERROR_SUCCESS)
705                 return ret;
706
707         if (standby)
708                 return CY_AS_ERROR_IN_STANDBY;
709
710         if (cy_as_device_is_in_suspend_mode(dev_p))
711                 return CY_AS_ERROR_IN_SUSPEND;
712
713         /*
714         * make sure we are in configuration mode
715         */
716         if ((cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_VM_SET) &
717                 CY_AS_MEM_P0_VM_SET_CFGMODE) == 0)
718                 return CY_AS_ERROR_NOT_IN_CONFIG_MODE;
719
720         /* Maximum firmware size is 24k */
721         if (size > CY_AS_MAXIMUM_FIRMWARE_SIZE)
722                 return CY_AS_ERROR_INVALID_SIZE;
723
724         /* Make sure the size is an even number of bytes as well */
725         if (size & 0x01)
726                 return CY_AS_ERROR_ALIGNMENT_ERROR;
727
728         /*
729          * write the two word header that gives the base address and
730          * size of the firmware image to download
731          */
732         state = cy_as_hal_disable_interrupts();
733         header = (uint8_t *)cy_as_hal_c_b_alloc(4);
734         cy_as_hal_enable_interrupts(state);
735         if (header == NULL)
736                 return CY_AS_ERROR_OUT_OF_MEMORY;
737
738         header[0] = 0x00;
739         header[1] = 0x00;
740         header[2] = (uint8_t)(size & 0xff);
741         header[3] = (uint8_t)((size >> 8) & 0xff);
742
743         /* Enable the firmware endpoint */
744         ret = cy_as_dma_enable_end_point(dev_p, CY_AS_FIRMWARE_ENDPOINT,
745                 cy_true, cy_as_direction_in);
746         if (ret != CY_AS_ERROR_SUCCESS)
747                 return ret;
748
749         /*
750         * setup DMA for 64 byte packets. this is the requirement for downloading
751         * firmware to west bridge.
752         */
753         cy_as_dma_set_max_dma_size(dev_p, CY_AS_FIRMWARE_ENDPOINT, 64);
754
755         if (cb)
756                 dmacb = my_dma_callback;
757
758         ret = cy_as_dma_queue_request(dev_p, CY_AS_FIRMWARE_ENDPOINT, header,
759                 4, cy_false, cy_false, dmacb);
760         if (ret != CY_AS_ERROR_SUCCESS)
761                 return ret;
762
763         /*
764         * write the firmware image to the west bridge device
765         */
766         ret = cy_as_dma_queue_request(dev_p, CY_AS_FIRMWARE_ENDPOINT,
767                 (void *)mem_p, size, cy_false, cy_false, dmacb);
768         if (ret != CY_AS_ERROR_SUCCESS)
769                 return ret;
770
771         if (cb) {
772                 cy_as_func_c_b_node *cbnode = cy_as_create_func_c_b_node_data(
773                         cb, client, CY_FUNCT_CB_MISC_DOWNLOADFIRMWARE, 0);
774
775                 if (cbnode == 0)
776                         return CY_AS_ERROR_OUT_OF_MEMORY;
777                 else
778                         cy_as_insert_c_b_node(dev_p->func_cbs_misc, cbnode);
779
780                 ret = cy_as_dma_kick_start(dev_p, CY_AS_FIRMWARE_ENDPOINT);
781                 if (ret != CY_AS_ERROR_SUCCESS)
782                         return ret;
783         } else {
784                 ret = cy_as_dma_drain_queue(dev_p,
785                         CY_AS_FIRMWARE_ENDPOINT, cy_true);
786
787                 /* Free the header memory that was allocated earlier. */
788                 cy_as_hal_c_b_free(header);
789
790                 if (ret != CY_AS_ERROR_SUCCESS)
791                         return ret;
792
793                 /*
794                 * disable EP 2. the storage module will
795                 * enable this EP if necessary.
796                 */
797                 cy_as_dma_enable_end_point(dev_p, CY_AS_FIRMWARE_ENDPOINT,
798                         cy_false, cy_as_direction_in);
799
800                 /*
801                 * clear the reset register.  this releases the west bridge
802                 * micro-controller from reset and begins running the code at
803                 * address zero.
804                 */
805                 cy_as_hal_write_register(dev_p->tag,
806                         CY_AS_MEM_RST_CTRL_REG, 0x00);
807         }
808
809         /*
810         * the firmware is not marked as loaded until the firmware
811         * initializes west bridge and a request is sent from west bridge
812         * to the P port processor indicating that west bridge is ready.
813         */
814         return CY_AS_ERROR_SUCCESS;
815 }
816
817
818 static cy_as_return_status_t
819 my_handle_response_get_firmware_version(cy_as_device *dev_p,
820                                 cy_as_ll_request_response *req_p,
821                                 cy_as_ll_request_response *reply_p,
822                                 cy_as_get_firmware_version_data *data_p)
823 {
824
825         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
826         uint16_t val;
827
828         if (cy_as_ll_request_response__get_code(reply_p)
829                 != CY_RESP_FIRMWARE_VERSION) {
830                 ret = CY_AS_ERROR_INVALID_RESPONSE;
831                 goto destroy;
832         }
833
834         data_p->major = cy_as_ll_request_response__get_word(reply_p, 0);
835         data_p->minor = cy_as_ll_request_response__get_word(reply_p, 1);
836         data_p->build = cy_as_ll_request_response__get_word(reply_p, 2);
837         val     = cy_as_ll_request_response__get_word(reply_p, 3);
838         data_p->media_type   = (uint8_t)(((val >> 8) & 0xFF) | (val & 0xFF));
839         val     = cy_as_ll_request_response__get_word(reply_p, 4);
840         data_p->is_debug_mode = (cy_bool)(val & 0xFF);
841
842 destroy:
843         cy_as_ll_destroy_request(dev_p, req_p);
844         cy_as_ll_destroy_response(dev_p, reply_p);
845
846         return ret;
847 }
848
849 cy_as_return_status_t
850 cy_as_misc_get_firmware_version(cy_as_device_handle handle,
851                                 cy_as_get_firmware_version_data *data,
852                                 cy_as_function_callback cb,
853                                 uint32_t client)
854 {
855         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
856         cy_bool standby;
857         cy_as_ll_request_response *req_p, *reply_p;
858
859         cy_as_device *dev_p;
860
861         (void)client;
862
863         cy_as_log_debug_message(6, "cy_as_misc_get_firmware_version called");
864
865         /* Make sure we have a valid device */
866         dev_p = (cy_as_device *)handle;
867         cy_as_check_device_ready(dev_p);
868
869         /*
870         * make sure antioch is not in standby
871         */
872         ret = cy_as_misc_in_standby(dev_p, &standby);
873         if (ret != CY_AS_ERROR_SUCCESS)
874                 return ret;
875         if (standby)
876                 return CY_AS_ERROR_IN_STANDBY;
877
878         /* Make sure the Antioch is not in suspend mode. */
879         if (cy_as_device_is_in_suspend_mode(dev_p))
880                 return CY_AS_ERROR_IN_SUSPEND;
881
882         /* Create the request to send to the West Bridge device */
883         req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_FIRMWARE_VERSION,
884                 CY_RQT_GENERAL_RQT_CONTEXT, 0);
885         if (req_p == 0)
886                 return CY_AS_ERROR_OUT_OF_MEMORY;
887
888         /*
889          * Reserve space for the reply, the reply data
890          * will not exceed three words
891          */
892         reply_p = cy_as_ll_create_response(dev_p, 5);
893         if (reply_p == 0) {
894                 cy_as_ll_destroy_request(dev_p, req_p);
895                 return CY_AS_ERROR_OUT_OF_MEMORY;
896         }
897
898         if (cb == 0) {
899                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
900                 if (ret != CY_AS_ERROR_SUCCESS)
901                         goto destroy;
902
903                 /* Request and response are freed in
904                  * MyHandleResponseGetFirmwareVersion. */
905                 ret = my_handle_response_get_firmware_version(dev_p,
906                         req_p, reply_p, data);
907                 return ret;
908         } else {
909
910                 ret = cy_as_misc_send_request(dev_p, cb, client,
911                         CY_FUNCT_CB_MISC_GETFIRMWAREVERSION, data,
912                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
913                         req_p, reply_p, cy_as_misc_func_callback);
914
915                 if (ret != CY_AS_ERROR_SUCCESS)
916                                 goto destroy;
917
918                 /* The request and response are freed
919                  * as part of the MiscFuncCallback */
920                 return ret;
921         }
922
923 destroy:
924         cy_as_ll_destroy_request(dev_p, req_p);
925         cy_as_ll_destroy_response(dev_p, reply_p);
926
927         return ret;
928 }
929 EXPORT_SYMBOL(cy_as_misc_get_firmware_version);
930
931 static cy_as_return_status_t
932 my_handle_response_read_m_c_u_register(cy_as_device *dev_p,
933                                 cy_as_ll_request_response *req_p,
934                                 cy_as_ll_request_response *reply_p,
935                                 uint8_t *data_p)
936 {
937
938         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
939
940         if (cy_as_ll_request_response__get_code(reply_p)
941                 != CY_RESP_MCU_REGISTER_DATA) {
942                 ret = CY_AS_ERROR_INVALID_RESPONSE;
943                 goto destroy;
944         }
945
946         *data_p = (uint8_t)
947                 (cy_as_ll_request_response__get_word(reply_p, 0));
948
949 destroy:
950         cy_as_ll_destroy_request(dev_p, req_p);
951         cy_as_ll_destroy_response(dev_p, reply_p);
952
953         return ret;
954 }
955
956 static cy_as_return_status_t
957 my_handle_response_get_gpio_value(cy_as_device *dev_p,
958                 cy_as_ll_request_response *req_p,
959                 cy_as_ll_request_response *reply_p,
960                 uint8_t *data_p)
961 {
962
963         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
964
965         if (cy_as_ll_request_response__get_code(reply_p)
966                 != CY_RESP_GPIO_STATE) {
967                 ret = CY_AS_ERROR_INVALID_RESPONSE;
968         } else
969                 *data_p = (uint8_t)
970                         (cy_as_ll_request_response__get_word(reply_p, 0));
971
972         cy_as_ll_destroy_request(dev_p, req_p);
973         cy_as_ll_destroy_response(dev_p, reply_p);
974
975         return ret;
976 }
977
978
979 cy_as_return_status_t cy_as_misc_set_sd_power_polarity(
980         cy_as_device_handle handle,
981         cy_as_misc_signal_polarity polarity,
982         cy_as_function_callback cb,
983         uint32_t client)
984 {
985         cy_as_ll_request_response *req_p, *reply_p;
986         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
987         cy_as_device *dev_p = (cy_as_device *)handle;
988
989         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
990                 return CY_AS_ERROR_INVALID_HANDLE;
991
992         if (!cy_as_device_is_configured(dev_p))
993                 return CY_AS_ERROR_NOT_CONFIGURED;
994
995         if (!cy_as_device_is_firmware_loaded(dev_p))
996                 return CY_AS_ERROR_NO_FIRMWARE;
997
998         if (cy_as_device_is_in_suspend_mode(dev_p))
999                 return CY_AS_ERROR_IN_SUSPEND;
1000
1001         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SDPOLARITY,
1002                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1003         if (req_p == 0)
1004                 return CY_AS_ERROR_OUT_OF_MEMORY;
1005
1006         cy_as_ll_request_response__set_word(req_p, 0,
1007                 (uint16_t)polarity);
1008
1009         /*
1010          * Reserve space for the reply, the reply data will
1011          * not exceed one word
1012          */
1013         reply_p = cy_as_ll_create_response(dev_p, 1);
1014         if (reply_p == 0) {
1015                 cy_as_ll_destroy_request(dev_p, req_p);
1016                 return CY_AS_ERROR_OUT_OF_MEMORY;
1017         }
1018
1019         if (cb == 0) {
1020                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1021                 if (ret != CY_AS_ERROR_SUCCESS)
1022                         goto destroy;
1023
1024                 return (my_handle_response_no_data(dev_p, req_p, reply_p));
1025         } else {
1026                 ret = cy_as_misc_send_request(dev_p, cb, client,
1027                         CY_FUNCT_CB_MISC_SETSDPOLARITY, 0, dev_p->func_cbs_misc,
1028                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1029                         cy_as_misc_func_callback);
1030
1031                 if (ret != CY_AS_ERROR_SUCCESS)
1032                         goto destroy;
1033
1034                 /* The request and response are freed
1035                  * as part of the FuncCallback */
1036                 return ret;
1037         }
1038
1039 destroy:
1040         cy_as_ll_destroy_request(dev_p, req_p);
1041         cy_as_ll_destroy_response(dev_p, reply_p);
1042         return ret;
1043 }
1044
1045
1046 cy_as_return_status_t
1047 cy_as_misc_read_m_c_u_register(cy_as_device_handle handle,
1048                                                   uint16_t address,
1049                                                   uint8_t *value,
1050                                                   cy_as_function_callback cb,
1051                                                   uint32_t client)
1052 {
1053         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1054         cy_as_ll_request_response *req_p, *reply_p;
1055
1056         cy_as_device *dev_p;
1057
1058         cy_as_log_debug_message(6, "cy_as_misc_read_m_c_u_register called");
1059
1060         dev_p = (cy_as_device *)handle;
1061         cy_as_check_device_ready(dev_p);
1062
1063         /* Check whether the firmware supports this command. */
1064         if (cy_as_device_is_nand_storage_supported(dev_p))
1065                 return CY_AS_ERROR_NOT_SUPPORTED;
1066
1067         /* Make sure the Antioch is not in suspend mode. */
1068         if (cy_as_device_is_in_suspend_mode(dev_p))
1069                 return CY_AS_ERROR_IN_SUSPEND;
1070
1071         /* Create the request to send to the West Bridge device */
1072         req_p = cy_as_ll_create_request(dev_p, CY_RQT_READ_MCU_REGISTER,
1073                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1074         if (req_p == 0)
1075                 return CY_AS_ERROR_OUT_OF_MEMORY;
1076
1077         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)address);
1078
1079         /* Reserve space for the reply, the reply
1080          * data will not exceed one word */
1081         reply_p = cy_as_ll_create_response(dev_p, 1);
1082         if (reply_p == 0) {
1083                 cy_as_ll_destroy_request(dev_p, req_p);
1084                 return CY_AS_ERROR_OUT_OF_MEMORY;
1085         }
1086
1087         if (cb == 0) {
1088                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1089                 if (ret != CY_AS_ERROR_SUCCESS)
1090                         goto destroy;
1091
1092                 if (cy_as_ll_request_response__get_code(reply_p) !=
1093                         CY_RESP_MCU_REGISTER_DATA) {
1094                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1095                         goto destroy;
1096                 }
1097
1098                 *value = (uint8_t)(cy_as_ll_request_response__get_word
1099                         (reply_p, 0));
1100         } else {
1101
1102                 ret = cy_as_misc_send_request(dev_p, cb, client,
1103                         CY_FUNCT_CB_MISC_READMCUREGISTER, value,
1104                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
1105                         req_p, reply_p, cy_as_misc_func_callback);
1106
1107                 if (ret != CY_AS_ERROR_SUCCESS)
1108                                 goto destroy;
1109
1110                 /* The request and response are freed
1111                  * as part of the MiscFuncCallback */
1112                 return ret;
1113         }
1114 destroy:
1115         cy_as_ll_destroy_request(dev_p, req_p);
1116         cy_as_ll_destroy_response(dev_p, reply_p);
1117
1118         return ret;
1119 }
1120 EXPORT_SYMBOL(cy_as_misc_read_m_c_u_register);
1121
1122 cy_as_return_status_t
1123 cy_as_misc_write_m_c_u_register(cy_as_device_handle handle,
1124                                                    uint16_t address,
1125                                                    uint8_t mask,
1126                                                    uint8_t value,
1127                                                    cy_as_function_callback cb,
1128                                                    uint32_t client)
1129 {
1130         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1131         cy_as_ll_request_response *req_p, *reply_p;
1132         cy_as_device *dev_p;
1133
1134         cy_as_log_debug_message(6, "cy_as_misc_write_m_c_u_register called");
1135
1136         dev_p = (cy_as_device *)handle;
1137         cy_as_check_device_ready(dev_p);
1138
1139         /* Check whether the firmware supports this command. */
1140         if (cy_as_device_is_nand_storage_supported(dev_p))
1141                 return CY_AS_ERROR_NOT_SUPPORTED;
1142
1143         /* Make sure the Antioch is not in suspend mode. */
1144         if (cy_as_device_is_in_suspend_mode(dev_p))
1145                 return CY_AS_ERROR_IN_SUSPEND;
1146
1147         /* Create the request to send to the West Bridge device */
1148         req_p = cy_as_ll_create_request(dev_p, CY_RQT_WRITE_MCU_REGISTER,
1149                 CY_RQT_GENERAL_RQT_CONTEXT, 2);
1150         if (req_p == 0)
1151                 return CY_AS_ERROR_OUT_OF_MEMORY;
1152
1153         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)address);
1154         cy_as_ll_request_response__set_word(req_p, 1,
1155                 (uint16_t)((mask << 8) | value));
1156
1157         /*
1158          * Reserve space for the reply, the reply data
1159          * will not exceed one word
1160          */
1161         reply_p = cy_as_ll_create_response(dev_p, 1);
1162         if (reply_p == 0) {
1163                 cy_as_ll_destroy_request(dev_p, req_p);
1164                 return CY_AS_ERROR_OUT_OF_MEMORY;
1165         }
1166
1167         if (cb == 0) {
1168                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1169                 if (ret != CY_AS_ERROR_SUCCESS)
1170                         goto destroy;
1171
1172                 if (cy_as_ll_request_response__get_code(reply_p) !=
1173                         CY_RESP_SUCCESS_FAILURE) {
1174                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1175                         goto destroy;
1176                 }
1177
1178                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1179         } else {
1180                 ret = cy_as_misc_send_request(dev_p, cb, client,
1181                         CY_FUNCT_CB_MISC_WRITEMCUREGISTER, 0,
1182                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
1183                         req_p, reply_p, cy_as_misc_func_callback);
1184
1185                 if (ret != CY_AS_ERROR_SUCCESS)
1186                         goto destroy;
1187
1188                 /*
1189                  * The request and response are freed as part of the
1190                  * MiscFuncCallback
1191                  */
1192                 return ret;
1193         }
1194
1195 destroy:
1196         cy_as_ll_destroy_request(dev_p, req_p);
1197         cy_as_ll_destroy_response(dev_p, reply_p);
1198
1199         return ret;
1200 }
1201
1202 cy_as_return_status_t
1203 my_handle_response_reset(cy_as_device *dev_p,
1204                                           cy_as_ll_request_response *req_p,
1205                                           cy_as_ll_request_response *reply_p,
1206                                           cy_as_reset_type type)
1207 {
1208         uint16_t   v;
1209
1210         (void)req_p;
1211         (void)reply_p;
1212
1213         /*
1214          * if the device is in suspend mode, it needs to be woken up
1215          * so that the write to the reset control register succeeds.
1216          * we need not however wait for the  wake up procedure to be
1217          * complete.
1218          */
1219         if (cy_as_device_is_in_suspend_mode(dev_p)) {
1220                 v = cy_as_hal_read_register(dev_p->tag,
1221                         CY_AS_MEM_CM_WB_CFG_ID);
1222                 cy_as_hal_sleep(1);
1223         }
1224
1225         if (type == cy_as_reset_hard) {
1226                 cy_as_misc_cancel_ex_requests(dev_p);
1227                 cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_RST_CTRL_REG,
1228                         CY_AS_MEM_RST_CTRL_REG_HARD);
1229                 cy_as_device_set_unconfigured(dev_p);
1230                 cy_as_device_set_firmware_not_loaded(dev_p);
1231                 cy_as_device_set_dma_stopped(dev_p);
1232                 cy_as_device_set_low_level_stopped(dev_p);
1233                 cy_as_device_set_intr_stopped(dev_p);
1234                 cy_as_device_clear_suspend_mode(dev_p);
1235                 cy_as_usb_cleanup(dev_p);
1236                 cy_as_storage_cleanup(dev_p);
1237
1238                 /*
1239                  * wait for a small amount of time to
1240                  * allow reset to be complete.
1241                  */
1242                 cy_as_hal_sleep(100);
1243         }
1244
1245         cy_as_device_clear_reset_pending(dev_p);
1246
1247         return CY_AS_ERROR_SUCCESS;
1248 }
1249
1250 cy_as_return_status_t
1251 cy_as_misc_reset(cy_as_device_handle handle,
1252                                 cy_as_reset_type type,
1253                                 cy_bool flush,
1254                                 cy_as_function_callback cb,
1255                                 uint32_t client)
1256 {
1257         cy_as_device *dev_p;
1258         cy_as_end_point_number_t i;
1259         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1260         (void)client;
1261         (void)cb;
1262
1263         cy_as_log_debug_message(6, "cy_as_misc_reset_e_x called");
1264
1265         /* Make sure the device is ready for the command. */
1266         dev_p = (cy_as_device *)handle;
1267         cy_as_check_device_ready(dev_p);
1268
1269         /*
1270          * soft reset is not supported until we close on the issues
1271          * in the firmware with what needs to happen.
1272          */
1273         if (type == cy_as_reset_soft)
1274                 return CY_AS_ERROR_NOT_YET_SUPPORTED;
1275
1276         cy_as_device_set_reset_pending(dev_p);
1277
1278         if (flush) {
1279                 /* Unable to DrainQueues in polling mode */
1280                 if ((dev_p->storage_cb || dev_p->storage_cb_ms) &&
1281                         cy_as_hal_is_polling())
1282                         return CY_AS_ERROR_ASYNC_PENDING;
1283
1284                 /*
1285                 * shutdown the endpoints so no more traffic can be queued
1286                 */
1287                 for (i = 0; i < 15; i++)
1288                         cy_as_dma_enable_end_point(dev_p, i, cy_false,
1289                                 cy_as_direction_dont_change);
1290
1291                 /*
1292                  * if we are in normal mode, drain all traffic across all
1293                  * endpoints to be sure all traffic is flushed. if the
1294                  * device is suspended, data will not be coming in on any
1295                  * endpoint and all outstanding DMA operations can be
1296                  * cancelled.
1297                  */
1298                 if (cy_as_device_is_in_suspend_mode(dev_p)) {
1299                         for (i = 0; i < 15; i++)
1300                                 cy_as_dma_cancel(dev_p, i,
1301                                         CY_AS_ERROR_CANCELED);
1302                 } else {
1303                         for (i = 0; i < 15; i++) {
1304                                 if ((i == CY_AS_P2S_WRITE_ENDPOINT) ||
1305                                         (i == CY_AS_P2S_READ_ENDPOINT))
1306                                         cy_as_dma_drain_queue(dev_p, i,
1307                                                 cy_false);
1308                                 else
1309                                         cy_as_dma_drain_queue(dev_p, i,
1310                                                 cy_true);
1311                         }
1312                 }
1313         } else {
1314                 /* No flush was requested, so cancel any outstanding DMAs
1315                  * so the user callbacks are called as needed
1316                  */
1317                 if (cy_as_device_is_storage_async_pending(dev_p)) {
1318                         for (i = 0; i < 15; i++)
1319                                 cy_as_dma_cancel(dev_p, i,
1320                                         CY_AS_ERROR_CANCELED);
1321                 }
1322         }
1323
1324         ret = my_handle_response_reset(dev_p, 0, 0, type);
1325
1326         if (cb)
1327                 /* Even though no mailbox communication was needed,
1328                  * issue the callback so the user does not need to
1329                  * special case their code. */
1330                 cb((cy_as_device_handle)dev_p, ret, client,
1331                         CY_FUNCT_CB_MISC_RESET, 0);
1332
1333         /*
1334          * initialize any registers that may have been
1335          * changed when the device was reset.
1336          */
1337         cy_as_hal_init_dev_registers(dev_p->tag, cy_false);
1338
1339         return ret;
1340 }
1341 EXPORT_SYMBOL(cy_as_misc_reset);
1342
1343 static cy_as_return_status_t
1344 get_unallocated_resource(cy_as_device *dev_p, cy_as_resource_type resource)
1345 {
1346         uint8_t shift = 0;
1347         uint16_t v;
1348         cy_as_return_status_t ret = CY_AS_ERROR_NOT_ACQUIRED;
1349
1350         switch (resource) {
1351         case cy_as_bus_u_s_b:
1352                 shift = 4;
1353                 break;
1354         case cy_as_bus_1:
1355                 shift = 0;
1356                 break;
1357         case cy_as_bus_0:
1358                 shift = 2;
1359                 break;
1360         default:
1361                 cy_as_hal_assert(cy_false);
1362                 break;
1363         }
1364
1365         /* Get the semaphore value for this resource */
1366         v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_RSE_ALLOCATE);
1367         v = (v >> shift) & 0x03;
1368
1369         if (v == 0x03) {
1370                 ret = CY_AS_ERROR_RESOURCE_ALREADY_OWNED;
1371         } else if ((v & 0x01) == 0) {
1372                 /* The resource is not owned by anyone, we can try to get it */
1373                 cy_as_hal_write_register(dev_p->tag,
1374                         CY_AS_MEM_P0_RSE_MASK, (0x03 << shift));
1375                 v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_RSE_MASK);
1376                 cy_as_hal_write_register(dev_p->tag,
1377                         CY_AS_MEM_P0_RSE_ALLOCATE, (0x01 << shift));
1378                 v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_RSE_MASK);
1379
1380                 v = cy_as_hal_read_register(dev_p->tag,
1381                         CY_AS_MEM_P0_RSE_ALLOCATE);
1382                 v = (v >> shift) & 0x03;
1383                 if (v == 0x03)
1384                         ret = CY_AS_ERROR_SUCCESS;
1385         }
1386
1387         return ret;
1388 }
1389
1390 static cy_as_return_status_t
1391 my_handle_response_acquire_resource(cy_as_device *dev_p,
1392                         cy_as_ll_request_response *req_p,
1393                         cy_as_ll_request_response *reply_p,
1394                         cy_as_resource_type *resource)
1395 {
1396         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1397
1398         if (cy_as_ll_request_response__get_code(reply_p) !=
1399                 CY_RESP_SUCCESS_FAILURE) {
1400                 ret = CY_AS_ERROR_INVALID_RESPONSE;
1401                 goto destroy;
1402         }
1403
1404         if (ret == CY_AS_ERROR_SUCCESS) {
1405                         ret = get_unallocated_resource(dev_p, *resource);
1406                         if (ret != CY_AS_ERROR_NOT_ACQUIRED)
1407                                 ret = CY_AS_ERROR_SUCCESS;
1408         }
1409
1410 destroy:
1411         cy_as_ll_destroy_request(dev_p, req_p);
1412         cy_as_ll_destroy_response(dev_p, reply_p);
1413
1414         return ret;
1415 }
1416
1417 cy_as_return_status_t
1418 cy_as_misc_acquire_resource(cy_as_device_handle handle,
1419                         cy_as_resource_type *resource,
1420                         cy_bool force,
1421                         cy_as_function_callback cb,
1422                         uint32_t client)
1423 {
1424         cy_as_ll_request_response *req_p, *reply_p;
1425         cy_as_return_status_t ret;
1426
1427         cy_as_device *dev_p;
1428
1429         (void)client;
1430
1431         cy_as_log_debug_message(6, "cy_as_misc_acquire_resource called");
1432
1433         if (*resource != cy_as_bus_u_s_b && *resource !=
1434                 cy_as_bus_0 && *resource != cy_as_bus_1)
1435                         return CY_AS_ERROR_INVALID_RESOURCE;
1436
1437
1438         /* Make sure the device is ready to accept the command. */
1439         dev_p = (cy_as_device *)handle;
1440         cy_as_check_device_ready(dev_p);
1441
1442         if (cy_as_device_is_in_suspend_mode(dev_p))
1443                 return CY_AS_ERROR_IN_SUSPEND;
1444
1445
1446         ret = get_unallocated_resource(dev_p, *resource);
1447
1448         /*
1449          * make sure that the callback is called if the resource is
1450          * successfully acquired at this point.
1451          */
1452         if ((ret == CY_AS_ERROR_SUCCESS) && (cb != 0))
1453                 cb(handle, ret, client,
1454                         CY_FUNCT_CB_MISC_ACQUIRERESOURCE, resource);
1455
1456         if (ret != CY_AS_ERROR_NOT_ACQUIRED)
1457                 return ret;
1458
1459         if (!force)
1460                 return CY_AS_ERROR_NOT_ACQUIRED;
1461
1462         /* Create the request to acquire the resource */
1463         req_p = cy_as_ll_create_request(dev_p, CY_RQT_ACQUIRE_RESOURCE,
1464                 CY_RQT_RESOURCE_RQT_CONTEXT, 1);
1465         if (req_p == 0)
1466                 return CY_AS_ERROR_OUT_OF_MEMORY;
1467
1468         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)(*resource));
1469
1470         reply_p = cy_as_ll_create_response(dev_p, 1);
1471         if (reply_p == 0) {
1472                 cy_as_ll_destroy_request(dev_p, req_p);
1473                 return CY_AS_ERROR_OUT_OF_MEMORY;
1474         }
1475
1476         if (cb == 0) {
1477                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1478                 if (ret != CY_AS_ERROR_SUCCESS)
1479                         goto destroy;
1480
1481                 if (cy_as_ll_request_response__get_code(reply_p) !=
1482                         CY_RESP_SUCCESS_FAILURE) {
1483                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1484                         goto destroy;
1485                 }
1486
1487                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1488         } else {
1489                         ret = cy_as_misc_send_request(dev_p, cb, client,
1490                                 CY_FUNCT_CB_MISC_ACQUIRERESOURCE, resource,
1491                                 dev_p->func_cbs_res, CY_AS_REQUEST_RESPONSE_EX,
1492                                 req_p, reply_p, cy_as_misc_func_callback);
1493
1494                         if (ret != CY_AS_ERROR_SUCCESS)
1495                                         goto destroy;
1496
1497                         /* The request and response are freed
1498                          * as part of the MiscFuncCallback */
1499                         return ret;
1500         }
1501
1502 destroy:
1503         cy_as_ll_destroy_request(dev_p, req_p);
1504         cy_as_ll_destroy_response(dev_p, reply_p);
1505
1506         if (ret == CY_AS_ERROR_SUCCESS) {
1507                 ret = get_unallocated_resource(dev_p, *resource);
1508                 if (ret != CY_AS_ERROR_NOT_ACQUIRED)
1509                         ret = CY_AS_ERROR_SUCCESS;
1510         }
1511
1512         return ret;
1513 }
1514 EXPORT_SYMBOL(cy_as_misc_acquire_resource);
1515
1516 cy_as_return_status_t
1517 cy_as_misc_release_resource(cy_as_device_handle handle,
1518         cy_as_resource_type resource)
1519 {
1520         uint8_t shift = 0;
1521         uint16_t v;
1522
1523         cy_as_device *dev_p;
1524
1525         cy_as_log_debug_message(6, "cy_as_misc_release_resource called");
1526
1527         /* Make sure the device is ready for the command. */
1528         dev_p = (cy_as_device *)handle;
1529         cy_as_check_device_ready(dev_p);
1530
1531         if (cy_as_device_is_in_suspend_mode(dev_p))
1532                 return CY_AS_ERROR_IN_SUSPEND;
1533
1534         if (resource != cy_as_bus_u_s_b && resource !=
1535                 cy_as_bus_0 && resource != cy_as_bus_1)
1536                 return CY_AS_ERROR_INVALID_RESOURCE;
1537
1538         switch (resource) {
1539         case cy_as_bus_u_s_b:
1540                 shift = 4;
1541                 break;
1542         case cy_as_bus_1:
1543                 shift = 0;
1544                 break;
1545         case cy_as_bus_0:
1546                 shift = 2;
1547                 break;
1548         default:
1549                 cy_as_hal_assert(cy_false);
1550                 break;
1551         }
1552
1553         /* Get the semaphore value for this resource */
1554         v = (cy_as_hal_read_register(dev_p->tag,
1555                 CY_AS_MEM_P0_RSE_ALLOCATE) >> shift) & 0x03;
1556         if (v == 0 || v == 1 || v == 2)
1557                 return CY_AS_ERROR_RESOURCE_NOT_OWNED;
1558
1559         cy_as_hal_write_register(dev_p->tag,
1560                 CY_AS_MEM_P0_RSE_MASK, (0x03 << shift));
1561         cy_as_hal_write_register(dev_p->tag,
1562                 CY_AS_MEM_P0_RSE_ALLOCATE, (0x02 << shift));
1563         cy_as_hal_write_register(dev_p->tag,
1564                 CY_AS_MEM_P0_RSE_MASK, 0);
1565
1566         return CY_AS_ERROR_SUCCESS;
1567 }
1568 EXPORT_SYMBOL(cy_as_misc_release_resource);
1569
1570 cy_as_return_status_t
1571 cy_as_misc_set_trace_level(cy_as_device_handle handle,
1572                                                 uint8_t level,
1573                                                 cy_as_bus_number_t bus,
1574                                                 uint32_t device,
1575                                                 uint32_t unit,
1576                                                 cy_as_function_callback cb,
1577                                                 uint32_t client)
1578 {
1579         cy_as_ll_request_response *req_p, *reply_p;
1580         cy_as_return_status_t ret;
1581         cy_as_device *dev_p;
1582
1583         cy_as_log_debug_message(6, "cy_as_misc_set_trace_level called");
1584
1585         /* Make sure the device is ready for the command. */
1586         dev_p = (cy_as_device *)handle;
1587         cy_as_check_device_ready(dev_p);
1588
1589         if (cy_as_device_is_in_suspend_mode(dev_p))
1590                 return CY_AS_ERROR_IN_SUSPEND;
1591
1592         if (bus < 0 || bus >= CY_AS_MAX_BUSES)
1593                 return CY_AS_ERROR_NO_SUCH_BUS;
1594
1595         if (device >= CY_AS_MAX_STORAGE_DEVICES)
1596                 return CY_AS_ERROR_NO_SUCH_DEVICE;
1597
1598         if (unit > 255)
1599                 return CY_AS_ERROR_NO_SUCH_UNIT;
1600
1601         if (level >= CYAS_FW_TRACE_MAX_LEVEL)
1602                 return CY_AS_ERROR_INVALID_TRACE_LEVEL;
1603
1604         /* Create the request to send to the West Bridge device */
1605         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_TRACE_LEVEL,
1606                 CY_RQT_GENERAL_RQT_CONTEXT, 2);
1607         if (req_p == 0)
1608                 return CY_AS_ERROR_OUT_OF_MEMORY;
1609
1610         cy_as_ll_request_response__set_word(req_p, 0,
1611                 (uint16_t)level);
1612         cy_as_ll_request_response__set_word(req_p, 1,
1613                 (uint16_t)((bus << 12) | (device << 8) | (unit)));
1614
1615         /*
1616          * Reserve space for the reply, the reply data will not
1617          * exceed three words
1618          */
1619         reply_p = cy_as_ll_create_response(dev_p, 2);
1620         if (reply_p == 0) {
1621                 cy_as_ll_destroy_request(dev_p, req_p);
1622                 return CY_AS_ERROR_OUT_OF_MEMORY;
1623         }
1624
1625         if (cb == 0) {
1626                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1627                 if (ret != CY_AS_ERROR_SUCCESS)
1628                         goto destroy;
1629
1630                 if (cy_as_ll_request_response__get_code(reply_p) !=
1631                         CY_RESP_SUCCESS_FAILURE) {
1632                         ret = CY_AS_ERROR_NOT_SUPPORTED;
1633                         goto destroy;
1634                 }
1635
1636                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1637         } else {
1638
1639                 ret = cy_as_misc_send_request(dev_p, cb, client,
1640                         CY_FUNCT_CB_MISC_SETTRACELEVEL, 0, dev_p->func_cbs_misc,
1641                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1642                         cy_as_misc_func_callback);
1643
1644                 if (ret != CY_AS_ERROR_SUCCESS)
1645                                 goto destroy;
1646
1647                 /* The request and response are freed as part of the
1648                  * MiscFuncCallback */
1649                 return ret;
1650         }
1651
1652 destroy:
1653         cy_as_ll_destroy_request(dev_p, req_p);
1654         cy_as_ll_destroy_response(dev_p, reply_p);
1655
1656         return ret;
1657 }
1658
1659 cy_as_return_status_t
1660 cy_as_misc_heart_beat_control(cy_as_device_handle handle,
1661                                                    cy_bool enable,
1662                                                    cy_as_function_callback cb,
1663                                                    uint32_t client)
1664 {
1665         cy_as_ll_request_response *req_p, *reply_p;
1666         cy_as_return_status_t ret;
1667         cy_as_device *dev_p;
1668
1669         cy_as_log_debug_message(6, "cy_as_misc_heart_beat_control called");
1670
1671         /* Make sure the device is ready for the command. */
1672         dev_p = (cy_as_device *)handle;
1673         cy_as_check_device_ready(dev_p);
1674
1675         if (cy_as_device_is_in_suspend_mode(dev_p))
1676                 return CY_AS_ERROR_IN_SUSPEND;
1677
1678         /* Create the request to send to the West Bridge device */
1679         req_p = cy_as_ll_create_request(dev_p, CY_RQT_CONTROL_ANTIOCH_HEARTBEAT,
1680                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1681         if (req_p == 0)
1682                 return CY_AS_ERROR_OUT_OF_MEMORY;
1683
1684         cy_as_ll_request_response__set_word(req_p, 0, (uint16_t)enable);
1685
1686         /* Reserve space for the reply, the reply
1687          * data will not exceed one word */
1688         reply_p = cy_as_ll_create_response(dev_p, 1);
1689         if (reply_p == 0) {
1690                 cy_as_ll_destroy_request(dev_p, req_p);
1691                 return CY_AS_ERROR_OUT_OF_MEMORY;
1692         }
1693
1694         if (cb == 0) {
1695                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1696                 if (ret != CY_AS_ERROR_SUCCESS)
1697                         goto destroy;
1698
1699                 if (cy_as_ll_request_response__get_code(reply_p) !=
1700                         CY_RESP_SUCCESS_FAILURE) {
1701                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1702                         goto destroy;
1703                 }
1704
1705                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1706         } else {
1707
1708                 ret = cy_as_misc_send_request(dev_p, cb, client,
1709                         CY_FUNCT_CB_MISC_HEARTBEATCONTROL, 0,
1710                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
1711                         req_p, reply_p, cy_as_misc_func_callback);
1712
1713                 if (ret != CY_AS_ERROR_SUCCESS)
1714                                 goto destroy;
1715
1716                 /* The request and response are freed as part of the
1717                  * MiscFuncCallback */
1718                 return ret;
1719         }
1720
1721 destroy:
1722         cy_as_ll_destroy_request(dev_p, req_p);
1723         cy_as_ll_destroy_response(dev_p, reply_p);
1724
1725         return ret;
1726 }
1727 EXPORT_SYMBOL(cy_as_misc_heart_beat_control);
1728
1729 static cy_as_return_status_t
1730 my_set_sd_clock_freq(
1731                 cy_as_device              *dev_p,
1732                 uint8_t                   card_type,
1733                 uint8_t                   setting,
1734                 cy_as_function_callback cb,
1735                 uint32_t                         client)
1736 {
1737         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1738         cy_as_ll_request_response *req_p, *reply_p;
1739
1740         if (cy_as_device_is_in_callback(dev_p) && (cb == 0))
1741                 return CY_AS_ERROR_INVALID_IN_CALLBACK;
1742
1743         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_SD_CLOCK_FREQ,
1744                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1745         if (req_p == 0)
1746                 return CY_AS_ERROR_OUT_OF_MEMORY;
1747
1748         cy_as_ll_request_response__set_word(req_p, 0,
1749                 (uint16_t)((card_type << 8) | setting));
1750
1751         /* Reserve space for the reply, which will not exceed one word. */
1752         reply_p = cy_as_ll_create_response(dev_p, 1);
1753         if (reply_p == 0) {
1754                 cy_as_ll_destroy_request(dev_p, req_p);
1755                 return CY_AS_ERROR_OUT_OF_MEMORY;
1756         }
1757
1758         if (cb == 0) {
1759                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1760                 if (ret != CY_AS_ERROR_SUCCESS)
1761                         goto destroy;
1762
1763                 if (cy_as_ll_request_response__get_code(reply_p) !=
1764                         CY_RESP_SUCCESS_FAILURE) {
1765                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1766                         goto destroy;
1767                 }
1768
1769                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
1770         } else {
1771                 ret = cy_as_misc_send_request(dev_p, cb, client,
1772                         CY_FUNCT_CB_MISC_SETSDFREQ, 0, dev_p->func_cbs_misc,
1773                         CY_AS_REQUEST_RESPONSE_EX, req_p, reply_p,
1774                         cy_as_misc_func_callback);
1775
1776                 if (ret != CY_AS_ERROR_SUCCESS)
1777                                 goto destroy;
1778
1779                 /* The request and response are freed as part of the
1780                  * MiscFuncCallback */
1781                 return ret;
1782         }
1783
1784 destroy:
1785         cy_as_ll_destroy_request(dev_p, req_p);
1786         cy_as_ll_destroy_response(dev_p, reply_p);
1787
1788         return ret;
1789 }
1790
1791 cy_as_return_status_t
1792 cy_as_misc_set_low_speed_sd_freq(
1793                 cy_as_device_handle      handle,
1794                 cy_as_low_speed_sd_freq   setting,
1795                 cy_as_function_callback cb,
1796                 uint32_t                         client)
1797 {
1798         cy_as_device *dev_p;
1799
1800         cy_as_log_debug_message(6, "cy_as_misc_set_low_speed_sd_freq called");
1801
1802         /* Make sure the device is ready for the command. */
1803         dev_p = (cy_as_device *)handle;
1804         cy_as_check_device_ready(dev_p);
1805
1806         if (cy_as_device_is_in_suspend_mode(dev_p))
1807                 return CY_AS_ERROR_IN_SUSPEND;
1808
1809         if ((setting != CY_AS_SD_DEFAULT_FREQ) &&
1810                 (setting != CY_AS_SD_RATED_FREQ))
1811                 return CY_AS_ERROR_INVALID_PARAMETER;
1812
1813         return my_set_sd_clock_freq(dev_p, 0, (uint8_t)setting, cb, client);
1814 }
1815 EXPORT_SYMBOL(cy_as_misc_set_low_speed_sd_freq);
1816
1817 cy_as_return_status_t
1818 cy_as_misc_set_high_speed_sd_freq(
1819                 cy_as_device_handle      handle,
1820                 cy_as_high_speed_sd_freq  setting,
1821                 cy_as_function_callback cb,
1822                 uint32_t                         client)
1823 {
1824         cy_as_device *dev_p;
1825
1826         cy_as_log_debug_message(6, "cy_as_misc_set_high_speed_sd_freq called");
1827
1828         /* Make sure the device is ready for the command. */
1829         dev_p = (cy_as_device *)handle;
1830         cy_as_check_device_ready(dev_p);
1831
1832         if (cy_as_device_is_in_suspend_mode(dev_p))
1833                 return CY_AS_ERROR_IN_SUSPEND;
1834
1835         if ((setting != CY_AS_HS_SD_FREQ_24) &&
1836                 (setting != CY_AS_HS_SD_FREQ_48))
1837                 return CY_AS_ERROR_INVALID_PARAMETER;
1838
1839         return my_set_sd_clock_freq(dev_p, 1, (uint8_t)setting, cb, client);
1840 }
1841 EXPORT_SYMBOL(cy_as_misc_set_high_speed_sd_freq);
1842
1843 cy_as_return_status_t
1844 cy_as_misc_get_gpio_value(cy_as_device_handle handle,
1845                 cy_as_misc_gpio pin,
1846                 uint8_t *value,
1847                 cy_as_function_callback cb,
1848                 uint32_t client)
1849 {
1850         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1851         cy_as_ll_request_response *req_p, *reply_p;
1852         cy_as_device *dev_p;
1853         uint16_t v;
1854
1855         cy_as_log_debug_message(6, "cy_as_misc_get_gpio_value called");
1856
1857         /* Make sure the device is ready for the command. */
1858         dev_p = (cy_as_device *)handle;
1859         cy_as_check_device_ready(dev_p);
1860
1861         /* If the pin specified is UVALID, there is no need
1862          * for firmware to be loaded. */
1863         if (pin == cy_as_misc_gpio_U_valid) {
1864                 v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PMU_UPDATE);
1865                 *value = (uint8_t)(v & CY_AS_MEM_PMU_UPDATE_UVALID);
1866
1867                 if (cb != 0)
1868                         cb(dev_p, ret, client,
1869                                 CY_FUNCT_CB_MISC_GETGPIOVALUE, value);
1870
1871                 return ret;
1872         }
1873
1874         /* Check whether the firmware supports this command. */
1875         if (cy_as_device_is_nand_storage_supported(dev_p))
1876                 return CY_AS_ERROR_NOT_SUPPORTED;
1877
1878         if (cy_as_device_is_in_suspend_mode(dev_p))
1879                 return CY_AS_ERROR_IN_SUSPEND;
1880
1881         /* Make sure the pin selected is valid */
1882         if ((pin != cy_as_misc_gpio_1) && (pin != cy_as_misc_gpio_0))
1883                 return CY_AS_ERROR_INVALID_PARAMETER;
1884
1885         req_p = cy_as_ll_create_request(dev_p, CY_RQT_GET_GPIO_STATE,
1886                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1887         if (req_p == 0)
1888                 return CY_AS_ERROR_OUT_OF_MEMORY;
1889
1890         cy_as_ll_request_response__set_word(req_p, 0, ((uint8_t)pin << 8));
1891
1892         /* Reserve space for the reply, which will not exceed one word. */
1893         reply_p = cy_as_ll_create_response(dev_p, 1);
1894         if (reply_p == 0) {
1895                 cy_as_ll_destroy_request(dev_p, req_p);
1896                 return CY_AS_ERROR_OUT_OF_MEMORY;
1897         }
1898
1899         if (cb == 0) {
1900                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
1901                 if (ret != CY_AS_ERROR_SUCCESS)
1902                         goto destroy;
1903
1904                 if (cy_as_ll_request_response__get_code(reply_p) !=
1905                         CY_RESP_GPIO_STATE) {
1906                         ret = CY_AS_ERROR_INVALID_RESPONSE;
1907                         goto destroy;
1908                 }
1909
1910                 *value = (uint8_t)
1911                         cy_as_ll_request_response__get_word(reply_p, 0);
1912         } else {
1913
1914                 ret = cy_as_misc_send_request(dev_p, cb, client,
1915                         CY_FUNCT_CB_MISC_GETGPIOVALUE, value,
1916                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
1917                         req_p, reply_p, cy_as_misc_func_callback);
1918
1919                 if (ret != CY_AS_ERROR_SUCCESS)
1920                                 goto destroy;
1921
1922                 /* The request and response are freed as part of the
1923                  * MiscFuncCallback */
1924                 return ret;
1925         }
1926
1927 destroy:
1928         cy_as_ll_destroy_request(dev_p, req_p);
1929         cy_as_ll_destroy_response(dev_p, reply_p);
1930
1931         return ret;
1932 }
1933 EXPORT_SYMBOL(cy_as_misc_get_gpio_value);
1934
1935 cy_as_return_status_t
1936 cy_as_misc_set_gpio_value(cy_as_device_handle handle,
1937                 cy_as_misc_gpio pin,
1938                 uint8_t value,
1939                 cy_as_function_callback cb,
1940                 uint32_t client)
1941 {
1942         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
1943         cy_as_ll_request_response *req_p, *reply_p;
1944         cy_as_device *dev_p;
1945         uint16_t v;
1946
1947         cy_as_log_debug_message(6, "cy_as_misc_set_gpio_value called");
1948
1949         /* Make sure the device is ready for the command. */
1950         dev_p = (cy_as_device *)handle;
1951         cy_as_check_device_ready(dev_p);
1952
1953         /* If the pin specified is UVALID, there is
1954          * no need for firmware to be loaded. */
1955         if (pin == cy_as_misc_gpio_U_valid) {
1956                 v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PMU_UPDATE);
1957                 if (value)
1958                         cy_as_hal_write_register(dev_p->tag,
1959                                 CY_AS_MEM_PMU_UPDATE,
1960                                 (v | CY_AS_MEM_PMU_UPDATE_UVALID));
1961                 else
1962                         cy_as_hal_write_register(dev_p->tag,
1963                                 CY_AS_MEM_PMU_UPDATE,
1964                                 (v & ~CY_AS_MEM_PMU_UPDATE_UVALID));
1965
1966                 if (cb != 0)
1967                         cb(dev_p, ret, client,
1968                                 CY_FUNCT_CB_MISC_SETGPIOVALUE, 0);
1969                 return ret;
1970         }
1971
1972         /* Check whether the firmware supports this command. */
1973         if (cy_as_device_is_nand_storage_supported(dev_p))
1974                 return CY_AS_ERROR_NOT_SUPPORTED;
1975
1976         if (cy_as_device_is_in_suspend_mode(dev_p))
1977                 return CY_AS_ERROR_IN_SUSPEND;
1978
1979         /* Make sure the pin selected is valid */
1980         if ((pin < cy_as_misc_gpio_0) || (pin > cy_as_misc_gpio_U_valid))
1981                 return CY_AS_ERROR_INVALID_PARAMETER;
1982
1983         /* Create and initialize the low level request to the firmware. */
1984         req_p = cy_as_ll_create_request(dev_p, CY_RQT_SET_GPIO_STATE,
1985                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
1986         if (req_p == 0)
1987                 return CY_AS_ERROR_OUT_OF_MEMORY;
1988
1989         v = (uint16_t)(((uint8_t)pin << 8) | (value > 0));
1990         cy_as_ll_request_response__set_word(req_p, 0, v);
1991
1992         /* Reserve space for the reply, which will not exceed one word. */
1993         reply_p = cy_as_ll_create_response(dev_p, 1);
1994         if (reply_p == 0) {
1995                 cy_as_ll_destroy_request(dev_p, req_p);
1996                 return CY_AS_ERROR_OUT_OF_MEMORY;
1997         }
1998
1999         if (cb == 0) {
2000                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2001                 if (ret != CY_AS_ERROR_SUCCESS)
2002                         goto destroy;
2003
2004                 if (cy_as_ll_request_response__get_code(reply_p) !=
2005                         CY_RESP_SUCCESS_FAILURE) {
2006                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2007                         goto destroy;
2008                 }
2009
2010                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
2011         } else {
2012
2013                 ret = cy_as_misc_send_request(dev_p, cb, client,
2014                         CY_FUNCT_CB_MISC_SETGPIOVALUE, 0,
2015                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
2016                         req_p, reply_p, cy_as_misc_func_callback);
2017
2018                 if (ret != CY_AS_ERROR_SUCCESS)
2019                                 goto destroy;
2020
2021                 /* The request and response are freed as part of the
2022                  * MiscFuncCallback */
2023                 return ret;
2024         }
2025
2026 destroy:
2027         cy_as_ll_destroy_request(dev_p, req_p);
2028         cy_as_ll_destroy_response(dev_p, reply_p);
2029
2030         return ret;
2031 }
2032 EXPORT_SYMBOL(cy_as_misc_set_gpio_value);
2033
2034 static cy_as_return_status_t
2035 my_enter_standby(cy_as_device *dev_p, cy_bool pin)
2036 {
2037         cy_as_misc_cancel_ex_requests(dev_p);
2038
2039         /* Save the current values in the critical P-port
2040          * registers, where necessary. */
2041         cy_as_hal_read_regs_before_standby(dev_p->tag);
2042
2043         if (pin) {
2044                 if (cy_as_hal_set_wakeup_pin(dev_p->tag, cy_false))
2045                         cy_as_device_set_pin_standby(dev_p);
2046                 else
2047                         return CY_AS_ERROR_SETTING_WAKEUP_PIN;
2048         } else {
2049                 /*
2050                  * put antioch in the standby mode
2051                  */
2052                 cy_as_hal_write_register(dev_p->tag,
2053                         CY_AS_MEM_PWR_MAGT_STAT, 0x02);
2054                 cy_as_device_set_register_standby(dev_p);
2055         }
2056
2057         /*
2058          * when the antioch comes out of standby, we have to wait until
2059          * the firmware initialization completes before sending other
2060          * requests down.
2061          */
2062         cy_as_device_set_firmware_not_loaded(dev_p);
2063
2064         /*
2065          * keep west bridge interrupt disabled until the device is being woken
2066          * up from standby.
2067          */
2068         dev_p->stby_int_mask = cy_as_hal_disable_interrupts();
2069
2070         return CY_AS_ERROR_SUCCESS;
2071 }
2072
2073 static cy_as_return_status_t
2074 my_handle_response_enter_standby(cy_as_device *dev_p,
2075                         cy_as_ll_request_response *req_p,
2076                         cy_as_ll_request_response *reply_p,
2077                         cy_bool pin)
2078 {
2079         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2080
2081         if (cy_as_ll_request_response__get_code(reply_p) !=
2082                 CY_RESP_SUCCESS_FAILURE) {
2083                 ret = CY_AS_ERROR_INVALID_RESPONSE;
2084                 goto destroy;
2085         }
2086
2087         ret = cy_as_ll_request_response__get_word(reply_p, 0);
2088
2089 destroy:
2090         cy_as_ll_destroy_request(dev_p, req_p);
2091         cy_as_ll_destroy_response(dev_p, reply_p);
2092
2093         if (ret != CY_AS_ERROR_SUCCESS)
2094                 return ret;
2095
2096         ret = my_enter_standby(dev_p, pin);
2097
2098         return ret;
2099 }
2100
2101 cy_as_return_status_t
2102 cy_as_misc_enter_standby(cy_as_device_handle handle,
2103                                                 cy_bool pin,
2104                                                 cy_as_function_callback cb,
2105                                                 uint32_t client)
2106 {
2107         cy_as_device *dev_p;
2108         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2109         cy_as_ll_request_response *req_p, *reply_p;
2110         cy_bool standby;
2111
2112         cy_as_log_debug_message(6, "cy_as_misc_enter_standby called");
2113
2114         /* Make sure we have a valid device */
2115         dev_p = (cy_as_device *)handle;
2116         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2117                 return CY_AS_ERROR_INVALID_HANDLE;
2118
2119         /*
2120          * if we already are in standby, do not do it again and let the
2121          * user know via the error return.
2122          */
2123         ret = cy_as_misc_in_standby(handle, &standby);
2124         if (ret != CY_AS_ERROR_SUCCESS)
2125                 return ret;
2126
2127         if (standby == cy_true)
2128                 return CY_AS_ERROR_ALREADY_STANDBY;
2129
2130         /*
2131          * if the user wants to transition from suspend mode to standby mode,
2132          * the device needs to be woken up so that it can complete all pending
2133          * operations.
2134          */
2135         if (cy_as_device_is_in_suspend_mode(dev_p))
2136                 cy_as_misc_leave_suspend(dev_p, 0, 0);
2137
2138         if (dev_p->usb_count) {
2139                 /*
2140                  * we do not allow west bridge to go into standby mode when the
2141                  * USB stack is initialized.  you must stop the USB stack in
2142                  * order to enter standby mode.
2143                  */
2144                 return CY_AS_ERROR_USB_RUNNING;
2145         }
2146
2147         /*
2148          * if the storage stack is not running, the device can directly be
2149          * put into sleep mode. otherwise, the firmware needs to be signaled
2150          * to prepare for going into sleep mode.
2151          */
2152         if (dev_p->storage_count) {
2153                 /*
2154                  * if there are async storage operations pending,
2155                  * make one attempt to complete them.
2156                  */
2157                 if (cy_as_device_is_storage_async_pending(dev_p)) {
2158                         /* DrainQueue will not work in polling mode */
2159                         if (cy_as_hal_is_polling())
2160                                 return CY_AS_ERROR_ASYNC_PENDING;
2161
2162                         cy_as_dma_drain_queue(dev_p,
2163                                 CY_AS_P2S_READ_ENDPOINT, cy_false);
2164                         cy_as_dma_drain_queue(dev_p,
2165                                 CY_AS_P2S_WRITE_ENDPOINT, cy_false);
2166
2167                         /*
2168                          * if more storage operations were queued
2169                          * at this stage, return an error.
2170                          */
2171                         if (cy_as_device_is_storage_async_pending(dev_p))
2172                                 return CY_AS_ERROR_ASYNC_PENDING;
2173                 }
2174
2175                 req_p = cy_as_ll_create_request(dev_p,
2176                         CY_RQT_PREPARE_FOR_STANDBY,
2177                         CY_RQT_GENERAL_RQT_CONTEXT, 1);
2178                 if (req_p == 0)
2179                         return CY_AS_ERROR_OUT_OF_MEMORY;
2180
2181                 reply_p = cy_as_ll_create_response(dev_p, 1);
2182                 if (reply_p == 0) {
2183                         cy_as_ll_destroy_request(dev_p, req_p);
2184                         return CY_AS_ERROR_OUT_OF_MEMORY;
2185                 }
2186
2187                 if (!cb) {
2188                         ret = cy_as_ll_send_request_wait_reply(dev_p,
2189                                 req_p, reply_p);
2190                         if (ret != CY_AS_ERROR_SUCCESS)
2191                                 goto destroy;
2192
2193                         /* The request and response are freed
2194                          * in the HandleResponse */
2195                         return my_handle_response_enter_standby(dev_p,
2196                                 req_p, reply_p, pin);
2197
2198                 } else {
2199                         ret = cy_as_misc_send_request(dev_p, cb, client,
2200                                 CY_FUNCT_CB_MISC_ENTERSTANDBY,  (void *)pin,
2201                                 dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
2202                                 req_p, reply_p, cy_as_misc_func_callback);
2203
2204                         if (ret != CY_AS_ERROR_SUCCESS)
2205                                 goto destroy;
2206
2207                         /* The request and response are freed
2208                          * as part of the MiscFuncCallback */
2209                         return ret;
2210                 }
2211 destroy:
2212                 cy_as_ll_destroy_request(dev_p, req_p);
2213                 cy_as_ll_destroy_response(dev_p, reply_p);
2214         } else {
2215                 ret = my_enter_standby(dev_p, pin);
2216                 if (cb)
2217                         /* Even though no mailbox communication was
2218                          * needed, issue the callback so the user
2219                          * does not need to special case their code. */
2220                         cb((cy_as_device_handle)dev_p, ret, client,
2221                                 CY_FUNCT_CB_MISC_ENTERSTANDBY, 0);
2222         }
2223
2224         return ret;
2225 }
2226 EXPORT_SYMBOL(cy_as_misc_enter_standby);
2227
2228 cy_as_return_status_t
2229 cy_as_misc_enter_standby_e_x_u(cy_as_device_handle handle,
2230                                                 cy_bool pin,
2231                                                 cy_bool uvalid_special,
2232                                                 cy_as_function_callback cb,
2233                                                 uint32_t client)
2234 {
2235         cy_as_device *dev_p;
2236
2237         dev_p = (cy_as_device *)handle;
2238         if (uvalid_special)
2239                 cy_as_hal_write_register(dev_p->tag, 0xc5, 0x4);
2240
2241         return cy_as_misc_enter_standby(handle, pin, cb, client);
2242 }
2243
2244 cy_as_return_status_t
2245 cy_as_misc_leave_standby(cy_as_device_handle handle,
2246         cy_as_resource_type resource)
2247 {
2248         cy_as_device *dev_p;
2249         uint16_t v;
2250         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2251         uint32_t count = 8;
2252         uint8_t  retry = 1;
2253
2254         cy_as_log_debug_message(6, "cy_as_misc_leave_standby called");
2255         (void)resource;
2256
2257         /* Make sure we have a valid device */
2258         dev_p = (cy_as_device *)handle;
2259         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2260                 return CY_AS_ERROR_INVALID_HANDLE;
2261
2262         if (cy_as_device_is_register_standby(dev_p)) {
2263                 /*
2264                  * set a flag to indicate that the west bridge is waking
2265                  * up from standby.
2266                  */
2267                 cy_as_device_set_waking(dev_p);
2268
2269                 /*
2270                  * the initial read will not succeed, but will just wake
2271                  * the west bridge device from standby.  successive reads
2272                  * should succeed and in that way we know west bridge is awake.
2273                  */
2274                 v = cy_as_hal_read_register(dev_p->tag,
2275                         CY_AS_MEM_CM_WB_CFG_ID);
2276
2277                 do {
2278                         /*
2279                          * we have initiated the operation to leave standby, now
2280                          * we need to wait at least N ms before trying to access
2281                          * the west bridge device to insure the PLLs have locked
2282                          * and we can talk to the device.
2283                          */
2284                         if (cy_as_device_is_crystal(dev_p))
2285                                 cy_as_hal_sleep(
2286                                         CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL);
2287                         else
2288                                 cy_as_hal_sleep(
2289                                         CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
2290                         v = cy_as_hal_read_register(dev_p->tag,
2291                                 CY_AS_MEM_CM_WB_CFG_ID);
2292
2293                         /*
2294                         * if the P-SPI interface mode is in use, there may be a
2295                         * need to re-synchronise the serial clock used for
2296                         * astoria access.
2297                         */
2298                         if (!is_valid_silicon_id(v)) {
2299                                 if (cy_as_hal_sync_device_clocks(dev_p->tag) !=
2300                                         cy_true) {
2301                                         cy_as_hal_enable_interrupts(
2302                                                 dev_p->stby_int_mask);
2303                                         return CY_AS_ERROR_TIMEOUT;
2304                                 }
2305                         }
2306                 } while (!is_valid_silicon_id(v) && count-- > 0);
2307
2308                 /*
2309                  * if we tried to read the register and could not,
2310                  * return a timeout
2311                  */
2312                 if (count == 0) {
2313                         cy_as_hal_enable_interrupts(
2314                                 dev_p->stby_int_mask);
2315                         return CY_AS_ERROR_TIMEOUT;
2316                 }
2317
2318                 /*
2319                  * the standby flag is cleared here, after the action to
2320                  * exit standby has been taken. the wait for firmware
2321                  * initialization, is ensured by marking the firmware as
2322                  * not loaded until the init event is received.
2323                  */
2324                 cy_as_device_clear_register_standby(dev_p);
2325
2326                 /*
2327                  * initialize any registers that may have been changed
2328                  * while the device was in standby mode.
2329                  */
2330                 cy_as_hal_init_dev_registers(dev_p->tag, cy_true);
2331         } else if (cy_as_device_is_pin_standby(dev_p)) {
2332                 /*
2333                  * set a flag to indicate that the west bridge is waking
2334                  * up from standby.
2335                  */
2336                 cy_as_device_set_waking(dev_p);
2337
2338 try_wakeup_again:
2339                 /*
2340                 * try to set the wakeup pin, if this fails in the HAL
2341                 * layer, return this failure to the user.
2342                 */
2343                 if (!cy_as_hal_set_wakeup_pin(dev_p->tag, cy_true)) {
2344                         cy_as_hal_enable_interrupts(dev_p->stby_int_mask);
2345                         return CY_AS_ERROR_SETTING_WAKEUP_PIN;
2346                 }
2347
2348                 /*
2349                 * we have initiated the operation to leave standby, now
2350                 * we need to wait at least N ms before trying to access
2351                 * the west bridge device to insure the PL_ls have locked
2352                 * and we can talk to the device.
2353                 */
2354                 if (cy_as_device_is_crystal(dev_p))
2355                         cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CRYSTAL);
2356                 else
2357                         cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
2358
2359                 /*
2360                  * initialize any registers that may have been changed
2361                  * while the device was in standby mode.
2362                  */
2363                 cy_as_hal_init_dev_registers(dev_p->tag, cy_true);
2364
2365                 /*
2366                  * the standby flag is cleared here, after the action to
2367                  * exit standby has been taken. the wait for firmware
2368                  * initialization, is ensured by marking the firmware as
2369                  * not loaded until the init event is received.
2370                  */
2371                 cy_as_device_clear_pin_standby(dev_p);
2372         } else {
2373                 return CY_AS_ERROR_NOT_IN_STANDBY;
2374         }
2375
2376         /*
2377          * the west bridge interrupt can be enabled now.
2378          */
2379         cy_as_hal_enable_interrupts(dev_p->stby_int_mask);
2380
2381         /*
2382          * release the west bridge micro-_controller from reset,
2383          * so that firmware initialization can complete. the attempt
2384          * to release antioch reset is made up to 8 times.
2385          */
2386         v = 0x03;
2387         count = 0x08;
2388         while ((v & 0x03) && (count)) {
2389                 cy_as_hal_write_register(dev_p->tag,
2390                         CY_AS_MEM_RST_CTRL_REG, 0x00);
2391                 v = cy_as_hal_read_register(dev_p->tag,
2392                         CY_AS_MEM_RST_CTRL_REG);
2393                 count--;
2394         }
2395
2396         if (v & 0x03) {
2397                 cy_as_hal_print_message("failed to clear antioch reset\n");
2398                 return CY_AS_ERROR_TIMEOUT;
2399         }
2400
2401         /*
2402          * if the wake-up pin is being used, wait here to make
2403          * sure that the wake-up event is received within a
2404          * reasonable delay. otherwise, toggle the wake-up pin
2405          * again in an attempt to start the firmware properly.
2406          */
2407         if (retry) {
2408                 count = 10;
2409                 while (count) {
2410                         /* If the wake-up event has been received,
2411                          * we can return. */
2412                         if (cy_as_device_is_firmware_loaded(dev_p))
2413                                 break;
2414                         /* If we are in polling mode, the interrupt may
2415                          * not have been serviced as yet. read the
2416                          * interrupt status register. if a pending mailbox
2417                          * interrupt is seen, we can assume that the
2418                          * wake-up event will be received soon. */
2419                         v = cy_as_hal_read_register(dev_p->tag,
2420                                 CY_AS_MEM_P0_INTR_REG);
2421                         if (v & CY_AS_MEM_P0_INTR_REG_MBINT)
2422                                 break;
2423
2424                         cy_as_hal_sleep(10);
2425                         count--;
2426                 }
2427
2428                 if (!count) {
2429                         retry = 0;
2430                         dev_p->stby_int_mask = cy_as_hal_disable_interrupts();
2431                         cy_as_hal_set_wakeup_pin(dev_p->tag, cy_false);
2432                         cy_as_hal_sleep(10);
2433                         goto try_wakeup_again;
2434                 }
2435         }
2436
2437         return ret;
2438 }
2439 EXPORT_SYMBOL(cy_as_misc_leave_standby);
2440
2441 cy_as_return_status_t
2442 cy_as_misc_register_callback(
2443                         /* Handle to the West Bridge device */
2444                         cy_as_device_handle handle,
2445                         /* The function to call */
2446                         cy_as_misc_event_callback  callback
2447                         )
2448 {
2449         cy_as_device *dev_p;
2450
2451         cy_as_log_debug_message(6, "cy_as_misc_register_callback called");
2452
2453         /* Make sure we have a valid device */
2454         dev_p = (cy_as_device *)handle;
2455         if (!dev_p || (dev_p->sig != CY_AS_DEVICE_HANDLE_SIGNATURE))
2456                 return CY_AS_ERROR_INVALID_HANDLE;
2457
2458         dev_p->misc_event_cb = callback;
2459         return CY_AS_ERROR_SUCCESS;
2460 }
2461
2462 cy_as_return_status_t
2463 cy_as_misc_storage_changed(cy_as_device_handle handle,
2464                                                  cy_as_function_callback   cb,
2465                                                  uint32_t client)
2466 {
2467         cy_as_device *dev_p;
2468         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2469         cy_bool standby;
2470         cy_as_ll_request_response *req_p, *reply_p;
2471
2472         cy_as_log_debug_message(6, "cy_as_misc_storage_changed called");
2473
2474         /* Make sure the device is ready for the command. */
2475         dev_p = (cy_as_device *)handle;
2476         cy_as_check_device_ready(dev_p);
2477
2478         /*
2479         * make sure antioch is not in standby
2480         */
2481         ret = cy_as_misc_in_standby(dev_p, &standby);
2482         if (ret != CY_AS_ERROR_SUCCESS)
2483                 return ret;
2484
2485         if (standby)
2486                 return CY_AS_ERROR_IN_STANDBY;
2487
2488         /*
2489          * make sure westbridge is not in suspend mode.
2490          */
2491         if (cy_as_device_is_in_suspend_mode(dev_p))
2492                 return CY_AS_ERROR_IN_SUSPEND;
2493
2494         /* Create the request to send to the West Bridge device */
2495         req_p = cy_as_ll_create_request(dev_p, CY_RQT_STORAGE_MEDIA_CHANGED,
2496                 CY_RQT_GENERAL_RQT_CONTEXT, 0);
2497         if (req_p == 0)
2498                 return CY_AS_ERROR_OUT_OF_MEMORY;
2499
2500         /* Reserve space for the reply, the reply data will
2501          * not exceed one word */
2502         reply_p = cy_as_ll_create_response(dev_p, 1);
2503         if (reply_p == 0) {
2504                 cy_as_ll_destroy_request(dev_p, req_p);
2505                 return CY_AS_ERROR_OUT_OF_MEMORY;
2506         }
2507
2508         if (cb == 0) {
2509                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2510                 if (ret != CY_AS_ERROR_SUCCESS)
2511                         goto destroy;
2512
2513                 if (cy_as_ll_request_response__get_code(reply_p) !=
2514                         CY_RESP_SUCCESS_FAILURE) {
2515                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2516                         goto destroy;
2517                 }
2518
2519                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
2520         } else {
2521
2522                 ret = cy_as_misc_send_request(dev_p, cb, client,
2523                         CY_FUNCT_CB_MISC_STORAGECHANGED, 0,
2524                         dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
2525                         req_p, reply_p, cy_as_misc_func_callback);
2526
2527                 if (ret != CY_AS_ERROR_SUCCESS)
2528                                 goto destroy;
2529
2530                 /* The request and response are freed as part of the
2531                  * MiscFuncCallback */
2532                 return ret;
2533         }
2534
2535 destroy:
2536         cy_as_ll_destroy_request(dev_p, req_p);
2537         cy_as_ll_destroy_response(dev_p, reply_p);
2538
2539         return ret;
2540 }
2541 EXPORT_SYMBOL(cy_as_misc_storage_changed);
2542
2543 cy_as_return_status_t
2544 cy_as_misc_enter_suspend(
2545                 cy_as_device_handle      handle,
2546                 cy_bool                    usb_wakeup_en,
2547                 cy_bool                    gpio_wakeup_en,
2548                 cy_as_function_callback cb,
2549                 uint32_t                         client)
2550 {
2551         cy_as_device *dev_p;
2552         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2553         cy_bool standby;
2554         cy_as_ll_request_response *req_p, *reply_p;
2555         uint16_t value;
2556         uint32_t int_state;
2557
2558         cy_as_log_debug_message(6, "cy_as_misc_enter_suspend called");
2559
2560         /*
2561          * basic sanity checks to ensure that the device is initialised.
2562          */
2563         dev_p = (cy_as_device *)handle;
2564         cy_as_check_device_ready(dev_p);
2565
2566         /*
2567          * make sure west bridge is not already in standby
2568          */
2569         cy_as_misc_in_standby(dev_p, &standby);
2570         if (standby)
2571                 return CY_AS_ERROR_IN_STANDBY;
2572
2573         /*
2574          * make sure that the device is not already in suspend mode.
2575          */
2576         if (cy_as_device_is_in_suspend_mode(dev_p))
2577                 return CY_AS_ERROR_IN_SUSPEND;
2578
2579         /*
2580          * make sure there is no active USB connection.
2581          */
2582         if ((cy_as_device_is_usb_connected(dev_p)) && (dev_p->usb_last_event
2583                 != cy_as_event_usb_suspend))
2584                 return CY_AS_ERROR_USB_CONNECTED;
2585
2586         /*
2587          * make sure that there are no async requests at this point in time.
2588          */
2589         int_state = cy_as_hal_disable_interrupts();
2590         if ((dev_p->func_cbs_misc->count) || (dev_p->func_cbs_res->count) ||
2591                 (dev_p->func_cbs_stor->count) || (dev_p->func_cbs_usb->count)) {
2592                 cy_as_hal_enable_interrupts(int_state);
2593                 return CY_AS_ERROR_ASYNC_PENDING;
2594         }
2595         cy_as_hal_enable_interrupts(int_state);
2596
2597         /* Create the request to send to the Antioch device */
2598         req_p = cy_as_ll_create_request(dev_p, CY_RQT_ENTER_SUSPEND_MODE,
2599                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
2600         if (req_p == 0)
2601                 return CY_AS_ERROR_OUT_OF_MEMORY;
2602
2603         /* Reserve space for the reply, the reply data will not
2604          * exceed one word */
2605         reply_p = cy_as_ll_create_response(dev_p, 1);
2606         if (reply_p == 0) {
2607                 cy_as_ll_destroy_request(dev_p, req_p);
2608                 return CY_AS_ERROR_OUT_OF_MEMORY;
2609         }
2610
2611         /* Wakeup control flags. */
2612         value = 0x0001;
2613         if (usb_wakeup_en)
2614                 value |= 0x04;
2615         if (gpio_wakeup_en)
2616                 value |= 0x02;
2617         cy_as_ll_request_response__set_word(req_p, 0, value);
2618
2619         if (cb != 0) {
2620
2621                 ret = cy_as_misc_send_request(dev_p, cb, client,
2622                         CY_FUNCT_CB_MISC_ENTERSUSPEND,
2623                         0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
2624                         req_p, reply_p,
2625                         cy_as_misc_func_callback);
2626
2627                 if (ret != CY_AS_ERROR_SUCCESS)
2628                                 goto destroy;
2629
2630                 return CY_AS_ERROR_SUCCESS;
2631         } else {
2632                 ret = cy_as_ll_send_request_wait_reply(dev_p, req_p, reply_p);
2633                 if (cy_as_ll_request_response__get_code(reply_p) !=
2634                         CY_RESP_SUCCESS_FAILURE)
2635                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2636                 else
2637                         ret = cy_as_ll_request_response__get_word(reply_p, 0);
2638         }
2639
2640 destroy:
2641         if (ret == CY_AS_ERROR_SUCCESS)
2642                 cy_as_device_set_suspend_mode(dev_p);
2643
2644         cy_as_ll_destroy_request(dev_p, req_p);
2645         cy_as_ll_destroy_response(dev_p, reply_p);
2646
2647         return ret;
2648 }
2649 EXPORT_SYMBOL(cy_as_misc_enter_suspend);
2650
2651 cy_as_return_status_t
2652 cy_as_misc_leave_suspend(
2653                 cy_as_device_handle      handle,
2654                 cy_as_function_callback cb,
2655                 uint32_t                         client)
2656 {
2657         cy_as_device *dev_p;
2658         uint16_t v, count;
2659         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2660
2661         cy_as_log_debug_message(6, "cy_as_misc_leave_suspend called");
2662
2663         /* Make sure we have a valid device */
2664         dev_p = (cy_as_device *)handle;
2665         cy_as_check_device_ready(dev_p);
2666
2667         /* Make sure we are in suspend mode. */
2668         if (cy_as_device_is_in_suspend_mode(dev_p)) {
2669                 if (cb) {
2670                         cy_as_func_c_b_node *cbnode =
2671                                 cy_as_create_func_c_b_node_data(cb, client,
2672                                 CY_FUNCT_CB_MISC_LEAVESUSPEND, 0);
2673                         if (cbnode == 0)
2674                                 return CY_AS_ERROR_OUT_OF_MEMORY;
2675
2676                         cy_as_insert_c_b_node(dev_p->func_cbs_misc, cbnode);
2677                 }
2678
2679                 /*
2680                  * do a read from the ID register so that the CE assertion
2681                  * will wake west bridge. the read is repeated until the
2682                  * read comes back with valid data.
2683                  */
2684                 count = 8;
2685
2686                 v = cy_as_hal_read_register(dev_p->tag,
2687                                 CY_AS_MEM_CM_WB_CFG_ID);
2688
2689                 while (!is_valid_silicon_id(v) && count-- > 0) {
2690                         cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
2691                         v = cy_as_hal_read_register(dev_p->tag,
2692                                         CY_AS_MEM_CM_WB_CFG_ID);
2693                 }
2694
2695                 /*
2696                  * if we tried to read the register and could not,
2697                  * return a timeout
2698                  */
2699                 if (count == 0)
2700                         return CY_AS_ERROR_TIMEOUT;
2701         } else
2702                 return CY_AS_ERROR_NOT_IN_SUSPEND;
2703
2704         if (cb == 0) {
2705                 /*
2706                  * wait until the in suspend mode flag is cleared.
2707                  */
2708                 count = 20;
2709                 while ((cy_as_device_is_in_suspend_mode(dev_p))
2710                         && (count--)) {
2711                         cy_as_hal_sleep(CY_AS_LEAVE_STANDBY_DELAY_CLOCK);
2712                 }
2713
2714                 if (cy_as_device_is_in_suspend_mode(dev_p))
2715                         ret = CY_AS_ERROR_TIMEOUT;
2716         }
2717
2718         return ret;
2719 }
2720 EXPORT_SYMBOL(cy_as_misc_leave_suspend);
2721
2722 cy_as_return_status_t
2723 cy_as_misc_reserve_l_n_a_boot_area(cy_as_device_handle handle,
2724                                                    uint8_t numzones,
2725                                                    cy_as_function_callback cb,
2726                                                    uint32_t client)
2727 {
2728         cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
2729         cy_bool standby;
2730         cy_as_ll_request_response *req_p, *reply_p;
2731
2732         cy_as_device *dev_p;
2733
2734         (void)client;
2735
2736         cy_as_log_debug_message(6, "cy_as_misc_switch_pnand_mode called");
2737
2738         /* Make sure we have a valid device */
2739         dev_p = (cy_as_device *)handle;
2740         cy_as_check_device_ready(dev_p);
2741
2742         /*
2743         * make sure antioch is not in standby
2744         */
2745         ret = cy_as_misc_in_standby(dev_p, &standby);
2746         if (ret != CY_AS_ERROR_SUCCESS)
2747                 return ret;
2748         if (standby)
2749                 return CY_AS_ERROR_IN_STANDBY;
2750
2751         /* Make sure the Antioch is not in suspend mode. */
2752         if (cy_as_device_is_in_suspend_mode(dev_p))
2753                 return CY_AS_ERROR_IN_SUSPEND;
2754
2755         /* Create the request to send to the West Bridge device */
2756         req_p = cy_as_ll_create_request(dev_p,
2757                 CY_RQT_RESERVE_LNA_BOOT_AREA,
2758                 CY_RQT_GENERAL_RQT_CONTEXT, 1);
2759         if (req_p == 0)
2760                         return CY_AS_ERROR_OUT_OF_MEMORY;
2761                 cy_as_ll_request_response__set_word(req_p,
2762                         0, (uint16_t)numzones);
2763
2764         /* Reserve space for the reply, the reply data will not
2765          * exceed one word */
2766         reply_p = cy_as_ll_create_response(dev_p, 1);
2767         if (reply_p == 0) {
2768                         cy_as_ll_destroy_request(dev_p, req_p);
2769                         return CY_AS_ERROR_OUT_OF_MEMORY;
2770         }
2771
2772         if (cb == 0) {
2773                 ret = cy_as_ll_send_request_wait_reply(dev_p,
2774                                 req_p, reply_p);
2775                 if (ret != CY_AS_ERROR_SUCCESS)
2776                         goto destroy;
2777
2778                 if (cy_as_ll_request_response__get_code(reply_p) !=
2779                         CY_RESP_SUCCESS_FAILURE) {
2780                         ret = CY_AS_ERROR_INVALID_RESPONSE;
2781                         goto destroy;
2782                 }
2783
2784                 ret = cy_as_ll_request_response__get_word(reply_p, 0);
2785         } else {
2786
2787                 ret = cy_as_misc_send_request(dev_p, cb, client,
2788                         CY_FUNCT_CB_MISC_RESERVELNABOOTAREA,
2789                         0, dev_p->func_cbs_misc, CY_AS_REQUEST_RESPONSE_EX,
2790                         req_p, reply_p, cy_as_misc_func_callback);
2791
2792                 if (ret != CY_AS_ERROR_SUCCESS)
2793                         goto destroy;
2794
2795                 /* The request and response are freed as part of the
2796                  * MiscFuncCallback */
2797                 return ret;
2798         }
2799
2800 destroy:
2801         cy_as_ll_destroy_request(dev_p, req_p);
2802         cy_as_ll_destroy_response(dev_p, reply_p);
2803
2804         return ret;
2805 }
2806
2807 cy_as_func_c_b_node*
2808 cy_as_create_func_c_b_node_data(cy_as_function_callback cb,
2809                                          uint32_t client,
2810                                          cy_as_funct_c_b_type type,
2811                                          void *data)
2812 {
2813         uint32_t state = cy_as_hal_disable_interrupts();
2814         cy_as_func_c_b_node *node = cy_as_hal_c_b_alloc(
2815                                         sizeof(cy_as_func_c_b_node));
2816         cy_as_hal_enable_interrupts(state);
2817         if (node != 0) {
2818                 node->node_type = CYAS_FUNC_CB;
2819                 node->cb_p = cb;
2820                 node->client_data = client;
2821                 node->data_type = type;
2822                 if (data != 0)
2823                         node->data_type |= CY_FUNCT_CB_DATA;
2824                 else
2825                         node->data_type |= CY_FUNCT_CB_NODATA;
2826                 node->data = data;
2827                 node->next_p = 0;
2828         }
2829         return node;
2830 }
2831
2832 cy_as_func_c_b_node*
2833 cy_as_create_func_c_b_node(cy_as_function_callback cb,
2834                                          uint32_t client)
2835 {
2836         return cy_as_create_func_c_b_node_data(cb, client,
2837                 CY_FUNCT_CB_NODATA, 0);
2838 }
2839
2840 void
2841 cy_as_destroy_func_c_b_node(cy_as_func_c_b_node *node)
2842 {
2843         uint32_t state;
2844
2845         node->node_type = CYAS_INVALID;
2846         state = cy_as_hal_disable_interrupts();
2847         cy_as_hal_c_b_free(node);
2848         cy_as_hal_enable_interrupts(state);
2849 }
2850
2851 cy_as_usb_func_c_b_node*
2852 cy_as_create_usb_func_c_b_node(
2853                 cy_as_usb_function_callback cb, uint32_t client)
2854 {
2855         uint32_t state = cy_as_hal_disable_interrupts();
2856         cy_as_usb_func_c_b_node *node = cy_as_hal_c_b_alloc(
2857                 sizeof(cy_as_usb_func_c_b_node));
2858         cy_as_hal_enable_interrupts(state);
2859         if (node != 0) {
2860                 node->type = CYAS_USB_FUNC_CB;
2861                 node->cb_p = cb;
2862                 node->client_data = client;
2863                 node->next_p = 0;
2864         }
2865         return node;
2866 }
2867
2868 void
2869 cy_as_destroy_usb_func_c_b_node(cy_as_usb_func_c_b_node *node)
2870 {
2871         uint32_t state;
2872
2873         node->type = CYAS_INVALID;
2874         state = cy_as_hal_disable_interrupts();
2875         cy_as_hal_c_b_free(node);
2876         cy_as_hal_enable_interrupts(state);
2877 }
2878
2879 cy_as_usb_io_c_b_node*
2880 cy_as_create_usb_io_c_b_node(cy_as_usb_io_callback cb)
2881 {
2882         uint32_t state = cy_as_hal_disable_interrupts();
2883         cy_as_usb_io_c_b_node *node = cy_as_hal_c_b_alloc(
2884                 sizeof(cy_as_usb_io_c_b_node));
2885         cy_as_hal_enable_interrupts(state);
2886         if (node != 0) {
2887                 node->type = CYAS_USB_IO_CB;
2888                 node->cb_p = cb;
2889                 node->next_p = 0;
2890         }
2891         return node;
2892 }
2893
2894 void
2895 cy_as_destroy_usb_io_c_b_node(cy_as_usb_io_c_b_node *node)
2896 {
2897         uint32_t state;
2898
2899         node->type = CYAS_INVALID;
2900
2901         state = cy_as_hal_disable_interrupts();
2902         cy_as_hal_c_b_free(node);
2903         cy_as_hal_enable_interrupts(state);
2904 }
2905
2906 cy_as_storage_io_c_b_node*
2907 cy_as_create_storage_io_c_b_node(cy_as_storage_callback cb,
2908         cy_as_media_type media, uint32_t device_index,
2909         uint32_t unit, uint32_t block_addr, cy_as_oper_type oper,
2910         cy_as_ll_request_response *req_p,
2911         cy_as_ll_request_response *reply_p)
2912 {
2913         uint32_t state = cy_as_hal_disable_interrupts();
2914         cy_as_storage_io_c_b_node *node = cy_as_hal_c_b_alloc(
2915                 sizeof(cy_as_storage_io_c_b_node));
2916         cy_as_hal_enable_interrupts(state);
2917         if (node != 0) {
2918                 node->type = CYAS_STORAGE_IO_CB;
2919                 node->cb_p = cb;
2920                 node->media = media;
2921                 node->device_index = device_index;
2922                 node->unit = unit;
2923                 node->block_addr = block_addr;
2924                 node->oper = oper;
2925                 node->req_p = req_p;
2926                 node->reply_p = reply_p;
2927                 node->next_p = 0;
2928         }
2929         return node;
2930 }
2931
2932 void
2933 cy_as_destroy_storage_io_c_b_node(cy_as_storage_io_c_b_node *node)
2934 {
2935         uint32_t state;
2936         node->type = CYAS_INVALID;
2937         state = cy_as_hal_disable_interrupts();
2938         cy_as_hal_c_b_free(node);
2939         cy_as_hal_enable_interrupts(state);
2940 }
2941
2942 cy_as_c_b_queue *
2943 cy_as_create_c_b_queue(cy_as_c_b_node_type type)
2944 {
2945         uint32_t state = cy_as_hal_disable_interrupts();
2946         cy_as_c_b_queue *queue = cy_as_hal_c_b_alloc(
2947                 sizeof(cy_as_c_b_queue));
2948         cy_as_hal_enable_interrupts(state);
2949         if (queue) {
2950                 queue->type = type;
2951                 queue->head_p = 0;
2952                 queue->tail_p = 0;
2953                 queue->count = 0;
2954         }
2955
2956         return queue;
2957 }
2958
2959 void
2960 cy_as_destroy_c_b_queue(cy_as_c_b_queue *queue)
2961 {
2962         uint32_t state;
2963         queue->type = CYAS_INVALID;
2964         queue->head_p = 0;
2965         queue->tail_p = 0;
2966         queue->count = 0;
2967         state = cy_as_hal_disable_interrupts();
2968         cy_as_hal_c_b_free(queue);
2969         cy_as_hal_enable_interrupts(state);
2970 }
2971
2972 /* Inserts a CyAsCBNode into the queue, the
2973  * node type must match the queue type*/
2974 void
2975 cy_as_insert_c_b_node(cy_as_c_b_queue *queue_p, void*cbnode)
2976 {
2977         uint32_t int_state;
2978
2979         int_state = cy_as_hal_disable_interrupts();
2980
2981         cy_as_hal_assert(queue_p != 0);
2982
2983         switch (queue_p->type) {
2984         case CYAS_USB_FUNC_CB:
2985                 {
2986                         cy_as_usb_func_c_b_node *node =
2987                                 (cy_as_usb_func_c_b_node *)cbnode;
2988                         cy_as_usb_func_c_b_node *tail =
2989                                 (cy_as_usb_func_c_b_node *)queue_p->tail_p;
2990
2991                         cy_as_hal_assert(node->type == CYAS_USB_FUNC_CB);
2992                         cy_as_hal_assert(tail == 0 ||
2993                                 tail->type == CYAS_USB_FUNC_CB);
2994                         if (queue_p->head_p == 0)
2995                                 queue_p->head_p = node;
2996                         else
2997                                 tail->next_p = node;
2998
2999                         queue_p->tail_p = node;
3000                 }
3001                 break;
3002
3003         case CYAS_USB_IO_CB:
3004                 {
3005                         cy_as_usb_io_c_b_node *node =
3006                                 (cy_as_usb_io_c_b_node *)cbnode;
3007                         cy_as_usb_io_c_b_node *tail =
3008                                 (cy_as_usb_io_c_b_node *)queue_p->tail_p;
3009
3010                         cy_as_hal_assert(node->type == CYAS_USB_IO_CB);
3011                         cy_as_hal_assert(tail == 0 ||
3012                                 tail->type == CYAS_USB_IO_CB);
3013                         if (queue_p->head_p == 0)
3014                                 queue_p->head_p = node;
3015                         else
3016                                 tail->next_p = node;
3017
3018                         queue_p->tail_p = node;
3019                 }
3020                 break;
3021
3022         case CYAS_STORAGE_IO_CB:
3023                 {
3024                         cy_as_storage_io_c_b_node *node =
3025                                 (cy_as_storage_io_c_b_node *)cbnode;
3026                         cy_as_storage_io_c_b_node *tail =
3027                                 (cy_as_storage_io_c_b_node *)queue_p->tail_p;
3028
3029                         cy_as_hal_assert(node->type == CYAS_STORAGE_IO_CB);
3030                         cy_as_hal_assert(tail == 0 ||
3031                                 tail->type == CYAS_STORAGE_IO_CB);
3032                         if (queue_p->head_p == 0)
3033                                 queue_p->head_p = node;
3034                         else
3035                                 tail->next_p = node;
3036
3037                                 queue_p->tail_p = node;
3038                 }
3039                 break;
3040
3041         case CYAS_FUNC_CB:
3042                 {
3043                         cy_as_func_c_b_node *node =
3044                                 (cy_as_func_c_b_node *)cbnode;
3045                         cy_as_func_c_b_node *tail =
3046                                 (cy_as_func_c_b_node *)queue_p->tail_p;
3047
3048                         cy_as_hal_assert(node->node_type == CYAS_FUNC_CB);
3049                         cy_as_hal_assert(tail == 0 ||
3050                                 tail->node_type == CYAS_FUNC_CB);
3051                         if (queue_p->head_p == 0)
3052                                 queue_p->head_p = node;
3053                         else
3054                                 tail->next_p = node;
3055
3056                                 queue_p->tail_p = node;
3057                 }
3058                 break;
3059
3060         default:
3061                 cy_as_hal_assert(cy_false);
3062                 break;
3063         }
3064
3065         queue_p->count++;
3066
3067         cy_as_hal_enable_interrupts(int_state);
3068 }
3069
3070 /* Removes the tail node from the queue and frees it */
3071 void
3072 cy_as_remove_c_b_tail_node(cy_as_c_b_queue *queue_p)
3073 {
3074         uint32_t int_state;
3075
3076         int_state = cy_as_hal_disable_interrupts();
3077
3078         if (queue_p->count > 0) {
3079                 /*
3080                  * the worst case length of the queue should be
3081                  * under 10 elements, and the average case should
3082                  * be just 1 element. so, we just employ a linear
3083                  * search to find the node to be freed.
3084                  */
3085                 switch (queue_p->type) {
3086                 case CYAS_FUNC_CB:
3087                         {
3088                                 cy_as_func_c_b_node *node =
3089                                         (cy_as_func_c_b_node *)
3090                                         queue_p->head_p;
3091                                 cy_as_func_c_b_node *tail =
3092                                         (cy_as_func_c_b_node *)
3093                                         queue_p->tail_p;
3094                                 if (node != tail) {
3095                                         while (node->next_p != tail)
3096                                                 node = node->next_p;
3097                                         node->next_p = 0;
3098                                         queue_p->tail_p = node;
3099                                 }
3100                                 cy_as_destroy_func_c_b_node(tail);
3101                         }
3102                         break;
3103
3104                 case CYAS_USB_FUNC_CB:
3105                         {
3106                                 cy_as_usb_func_c_b_node *node =
3107                                         (cy_as_usb_func_c_b_node *)
3108                                         queue_p->head_p;
3109                                 cy_as_usb_func_c_b_node *tail =
3110                                         (cy_as_usb_func_c_b_node *)
3111                                         queue_p->tail_p;
3112                                 if (node != tail) {
3113                                         while (node->next_p != tail)
3114                                                         node = node->next_p;
3115                                                 node->next_p = 0;
3116                                                 queue_p->tail_p = node;
3117                                 }
3118
3119                                 cy_as_destroy_usb_func_c_b_node(tail);
3120                         }
3121                         break;
3122
3123                 case CYAS_USB_IO_CB:
3124                         {
3125                                 cy_as_usb_io_c_b_node *node =
3126                                         (cy_as_usb_io_c_b_node *)
3127                                         queue_p->head_p;
3128                                 cy_as_usb_io_c_b_node *tail =
3129                                         (cy_as_usb_io_c_b_node *)
3130                                         queue_p->tail_p;
3131                                 if (node != tail) {
3132                                         while (node->next_p != tail)
3133                                                 node = node->next_p;
3134                                         node->next_p = 0;
3135                                         queue_p->tail_p = node;
3136                                 }
3137                                 cy_as_destroy_usb_io_c_b_node(tail);
3138                         }
3139                         break;
3140
3141                 case CYAS_STORAGE_IO_CB:
3142                         {
3143                                 cy_as_storage_io_c_b_node *node =
3144                                         (cy_as_storage_io_c_b_node *)
3145                                         queue_p->head_p;
3146                                 cy_as_storage_io_c_b_node *tail =
3147                                         (cy_as_storage_io_c_b_node *)
3148                                         queue_p->tail_p;
3149                                 if (node != tail) {
3150                                         while (node->next_p != tail)
3151                                                 node = node->next_p;
3152                                         node->next_p = 0;
3153                                         queue_p->tail_p = node;
3154                                 }
3155                                 cy_as_destroy_storage_io_c_b_node(tail);
3156                         }
3157                         break;
3158
3159                 default:
3160                         cy_as_hal_assert(cy_false);
3161                 }
3162
3163                 queue_p->count--;
3164                 if (queue_p->count == 0) {
3165                         queue_p->head_p = 0;
3166                         queue_p->tail_p = 0;
3167                 }
3168         }
3169
3170         cy_as_hal_enable_interrupts(int_state);
3171 }
3172
3173 /* Removes the first CyAsCBNode from the queue and frees it */
3174 void
3175 cy_as_remove_c_b_node(cy_as_c_b_queue *queue_p)
3176 {
3177         uint32_t int_state;
3178
3179         int_state = cy_as_hal_disable_interrupts();
3180
3181         cy_as_hal_assert(queue_p->count >= 0);
3182         if (queue_p->count > 0) {
3183                 if (queue_p->type == CYAS_USB_FUNC_CB) {
3184                         cy_as_usb_func_c_b_node *node =
3185                                 (cy_as_usb_func_c_b_node *)
3186                                 queue_p->head_p;
3187                         queue_p->head_p = node->next_p;
3188                         cy_as_destroy_usb_func_c_b_node(node);
3189                 } else if (queue_p->type == CYAS_USB_IO_CB) {
3190                         cy_as_usb_io_c_b_node *node =
3191                                 (cy_as_usb_io_c_b_node *)
3192                                 queue_p->head_p;
3193                         queue_p->head_p = node->next_p;
3194                         cy_as_destroy_usb_io_c_b_node(node);
3195                 } else if (queue_p->type == CYAS_STORAGE_IO_CB) {
3196                         cy_as_storage_io_c_b_node *node =
3197                                 (cy_as_storage_io_c_b_node *)
3198                                 queue_p->head_p;
3199                         queue_p->head_p = node->next_p;
3200                         cy_as_destroy_storage_io_c_b_node(node);
3201                 } else if (queue_p->type == CYAS_FUNC_CB) {
3202                         cy_as_func_c_b_node *node =
3203                                 (cy_as_func_c_b_node *)
3204                                 queue_p->head_p;
3205                         queue_p->head_p = node->next_p;
3206                         cy_as_destroy_func_c_b_node(node);
3207                 } else {
3208                         cy_as_hal_assert(cy_false);
3209                 }
3210
3211                 queue_p->count--;
3212                 if (queue_p->count == 0) {
3213                         queue_p->head_p = 0;
3214                         queue_p->tail_p = 0;
3215                 }
3216         }
3217
3218         cy_as_hal_enable_interrupts(int_state);
3219 }
3220
3221 void my_print_func_c_b_node(cy_as_func_c_b_node *node)
3222 {
3223         cy_as_funct_c_b_type type =
3224                 cy_as_funct_c_b_type_get_type(node->data_type);
3225         cy_as_hal_print_message("[cd:%2u dt:%2u cb:0x%08x "
3226                 "d:0x%08x nt:%1i]", node->client_data, type,
3227                 (uint32_t)node->cb_p, (uint32_t)node->data,
3228                 node->node_type);
3229 }
3230
3231 void my_print_c_b_queue(cy_as_c_b_queue *queue_p)
3232 {
3233         uint32_t i = 0;
3234
3235         cy_as_hal_print_message("| count: %u type: ", queue_p->count);
3236
3237         if (queue_p->type == CYAS_USB_FUNC_CB) {
3238                 cy_as_hal_print_message("USB_FUNC_CB\n");
3239         } else if (queue_p->type == CYAS_USB_IO_CB) {
3240                 cy_as_hal_print_message("USB_IO_CB\n");
3241         } else if (queue_p->type == CYAS_STORAGE_IO_CB) {
3242                 cy_as_hal_print_message("STORAGE_IO_CB\n");
3243         } else if (queue_p->type == CYAS_FUNC_CB) {
3244                 cy_as_func_c_b_node *node = queue_p->head_p;
3245                 cy_as_hal_print_message("FUNC_CB\n");
3246                 if (queue_p->count > 0) {
3247                         cy_as_hal_print_message("| head->");
3248
3249                         for (i = 0; i < queue_p->count; i++) {
3250                                 if (node) {
3251                                         cy_as_hal_print_message("->");
3252                                         my_print_func_c_b_node(node);
3253                                         node = node->next_p;
3254                                 } else
3255                                         cy_as_hal_print_message("->[NULL]\n");
3256                         }
3257
3258                         cy_as_hal_print_message("\n| tail->");
3259                         my_print_func_c_b_node(queue_p->tail_p);
3260                         cy_as_hal_print_message("\n");
3261                 }
3262         } else {
3263                 cy_as_hal_print_message("INVALID\n");
3264         }
3265
3266         cy_as_hal_print_message("|----------\n");
3267 }
3268
3269
3270 /* Removes and frees all pending callbacks */
3271 void
3272 cy_as_clear_c_b_queue(cy_as_c_b_queue *queue_p)
3273 {
3274         uint32_t int_state = cy_as_hal_disable_interrupts();
3275
3276         while (queue_p->count != 0)
3277                 cy_as_remove_c_b_node(queue_p);
3278
3279         cy_as_hal_enable_interrupts(int_state);
3280 }
3281
3282 cy_as_return_status_t
3283 cy_as_misc_send_request(cy_as_device *dev_p,
3284                                           cy_as_function_callback cb,
3285                                           uint32_t client,
3286                                           cy_as_funct_c_b_type type,
3287                                           void *data,
3288                                           cy_as_c_b_queue *queue,
3289                                           uint16_t req_type,
3290                                           cy_as_ll_request_response *req_p,
3291                                           cy_as_ll_request_response *reply_p,
3292                                           cy_as_response_callback rcb)
3293 {
3294
3295         cy_as_func_c_b_node *cbnode = cy_as_create_func_c_b_node_data(cb,
3296                 client, type, data);
3297         cy_as_return_status_t ret;
3298
3299         if (cbnode == 0)
3300                 return CY_AS_ERROR_OUT_OF_MEMORY;
3301         else
3302                 cy_as_insert_c_b_node(queue, cbnode);
3303
3304         req_p->flags |= req_type;
3305
3306         ret = cy_as_ll_send_request(dev_p, req_p, reply_p, cy_false, rcb);
3307         if (ret != CY_AS_ERROR_SUCCESS)
3308                 cy_as_remove_c_b_tail_node(queue);
3309
3310         return ret;
3311 }
3312
3313 void
3314 cy_as_misc_cancel_ex_requests(cy_as_device *dev_p)
3315 {
3316         int i;
3317         for (i = 0; i < CY_RQT_CONTEXT_COUNT; i++)
3318                 cy_as_ll_remove_all_requests(dev_p, dev_p->context[i]);
3319 }
3320
3321
3322 static void
3323 cy_as_misc_func_callback(cy_as_device *dev_p,
3324                                                 uint8_t context,
3325                                                 cy_as_ll_request_response *rqt,
3326                                                 cy_as_ll_request_response *resp,
3327                                                 cy_as_return_status_t stat)
3328 {
3329         cy_as_func_c_b_node *node = NULL;
3330         cy_as_return_status_t ret;
3331
3332         cy_bool ex_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_EX)
3333                         == CY_AS_REQUEST_RESPONSE_EX;
3334         cy_bool ms_request = (rqt->flags & CY_AS_REQUEST_RESPONSE_MS)
3335                         == CY_AS_REQUEST_RESPONSE_MS;
3336         uint8_t code;
3337         uint32_t type;
3338         uint8_t cntxt;
3339
3340         cy_as_hal_assert(ex_request || ms_request);
3341         (void) ex_request;
3342         (void) ms_request;
3343         (void)context;
3344
3345         cntxt = cy_as_ll_request_response__get_context(rqt);
3346         code = cy_as_ll_request_response__get_code(rqt);
3347
3348         switch (cntxt) {
3349         case CY_RQT_GENERAL_RQT_CONTEXT:
3350                 cy_as_hal_assert(dev_p->func_cbs_misc->count != 0);
3351                 cy_as_hal_assert(dev_p->func_cbs_misc->type == CYAS_FUNC_CB);
3352                 node = (cy_as_func_c_b_node *)dev_p->func_cbs_misc->head_p;
3353                 type = cy_as_funct_c_b_type_get_type(node->data_type);
3354
3355                 switch (code) {
3356                 case CY_RQT_GET_FIRMWARE_VERSION:
3357                         cy_as_hal_assert(node->data != 0);
3358                         cy_as_hal_assert(type ==
3359                                 CY_FUNCT_CB_MISC_GETFIRMWAREVERSION);
3360                         ret = my_handle_response_get_firmware_version(dev_p,
3361                                 rqt, resp,
3362                                 (cy_as_get_firmware_version_data *)node->data);
3363                         break;
3364                 case CY_RQT_READ_MCU_REGISTER:
3365                         cy_as_hal_assert(node->data != 0);
3366                         cy_as_hal_assert(type ==
3367                                 CY_FUNCT_CB_MISC_READMCUREGISTER);
3368                         ret = my_handle_response_read_m_c_u_register(dev_p, rqt,
3369                                 resp, (uint8_t *)node->data);
3370                         break;
3371                 case CY_RQT_GET_GPIO_STATE:
3372                         cy_as_hal_assert(node->data != 0);
3373                         cy_as_hal_assert(type ==
3374                                 CY_FUNCT_CB_MISC_GETGPIOVALUE);
3375                         ret = my_handle_response_get_gpio_value(dev_p, rqt,
3376                                 resp, (uint8_t *)node->data);
3377                         break;
3378                 case CY_RQT_SET_SD_CLOCK_FREQ:
3379                         cy_as_hal_assert(type == CY_FUNCT_CB_MISC_SETSDFREQ);
3380                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3381                         break;
3382                 case CY_RQT_CONTROL_ANTIOCH_HEARTBEAT:
3383                         cy_as_hal_assert(type ==
3384                                 CY_FUNCT_CB_MISC_HEARTBEATCONTROL);
3385                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3386                         break;
3387                 case CY_RQT_WRITE_MCU_REGISTER:
3388                         cy_as_hal_assert(type ==
3389                                 CY_FUNCT_CB_MISC_WRITEMCUREGISTER);
3390                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3391                         break;
3392                 case CY_RQT_STORAGE_MEDIA_CHANGED:
3393                         cy_as_hal_assert(type ==
3394                                 CY_FUNCT_CB_MISC_STORAGECHANGED);
3395                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3396                         break;
3397                 case CY_RQT_SET_GPIO_STATE:
3398                         cy_as_hal_assert(type ==
3399                                 CY_FUNCT_CB_MISC_SETGPIOVALUE);
3400                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3401                         break;
3402                 case CY_RQT_SET_TRACE_LEVEL:
3403                         cy_as_hal_assert(type ==
3404                                 CY_FUNCT_CB_MISC_SETTRACELEVEL);
3405                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3406                         if (ret == CY_AS_ERROR_INVALID_RESPONSE)
3407                                 ret = CY_AS_ERROR_NOT_SUPPORTED;
3408                         break;
3409                 case CY_RQT_PREPARE_FOR_STANDBY:
3410                         cy_as_hal_assert(type ==
3411                                 CY_FUNCT_CB_MISC_ENTERSTANDBY);
3412                         ret = my_handle_response_enter_standby(dev_p, rqt, resp,
3413                                 (cy_bool)node->data);
3414                         break;
3415                 case CY_RQT_ENTER_SUSPEND_MODE:
3416                         cy_as_hal_assert(type ==
3417                                 CY_FUNCT_CB_MISC_ENTERSUSPEND);
3418                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3419                         if (ret == CY_AS_ERROR_SUCCESS)
3420                                 cy_as_device_set_suspend_mode(dev_p);
3421
3422                         break;
3423                 case CY_RQT_RESERVE_LNA_BOOT_AREA:
3424                         cy_as_hal_assert(type ==
3425                                 CY_FUNCT_CB_MISC_RESERVELNABOOTAREA);
3426                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3427                         break;
3428                 case CY_RQT_SDPOLARITY:
3429                         cy_as_hal_assert(type ==
3430                                 CY_FUNCT_CB_MISC_SETSDPOLARITY);
3431                         ret = my_handle_response_no_data(dev_p, rqt, resp);
3432                         break;
3433                 default:
3434                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3435                         cy_as_hal_assert(cy_false);
3436                         break;
3437                 }
3438                 break;
3439
3440         case CY_RQT_RESOURCE_RQT_CONTEXT:
3441                 cy_as_hal_assert(dev_p->func_cbs_res->count != 0);
3442                 cy_as_hal_assert(dev_p->func_cbs_res->type == CYAS_FUNC_CB);
3443                 node = (cy_as_func_c_b_node *)dev_p->func_cbs_res->head_p;
3444                 type = cy_as_funct_c_b_type_get_type(node->data_type);
3445
3446                 switch (code) {
3447                 case CY_RQT_ACQUIRE_RESOURCE:
3448                         /* The node->data field is actually an enum value
3449                          * which could be 0, thus no assert is done */
3450                         cy_as_hal_assert(type ==
3451                                 CY_FUNCT_CB_MISC_ACQUIRERESOURCE);
3452                         ret = my_handle_response_acquire_resource(dev_p, rqt,
3453                                 resp, (cy_as_resource_type *)node->data);
3454                         break;
3455                 default:
3456                         ret = CY_AS_ERROR_INVALID_RESPONSE;
3457                         cy_as_hal_assert(cy_false);
3458                         break;
3459                 }
3460                 break;
3461
3462         default:
3463                 ret = CY_AS_ERROR_INVALID_RESPONSE;
3464                 cy_as_hal_assert(cy_false);
3465                 break;
3466         }
3467
3468         /*
3469          * if the low level layer returns a direct error, use the
3470          * corresponding error code. if not, use the error code
3471          * based on the response from firmware.
3472          */
3473         if (stat == CY_AS_ERROR_SUCCESS)
3474                 stat = ret;
3475
3476         /* Call the user Callback */
3477         node->cb_p((cy_as_device_handle)dev_p, stat, node->client_data,
3478                 node->data_type, node->data);
3479         if (cntxt == CY_RQT_GENERAL_RQT_CONTEXT)
3480                 cy_as_remove_c_b_node(dev_p->func_cbs_misc);
3481         else
3482                 cy_as_remove_c_b_node(dev_p->func_cbs_res);
3483
3484 }
3485
3486
3487
3488 /*[]*/