root/drivers/nfc/nfcmrvl/fw_dnld.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. alloc_lc_skb
  2. fw_dnld_over
  3. fw_dnld_timeout
  4. process_state_reset
  5. process_state_init
  6. create_lc
  7. process_state_set_ref_clock
  8. process_state_set_hi_config
  9. process_state_open_lc
  10. process_state_fw_dnld
  11. process_state_close_lc
  12. process_state_boot
  13. fw_dnld_rx_work
  14. nfcmrvl_fw_dnld_init
  15. nfcmrvl_fw_dnld_deinit
  16. nfcmrvl_fw_dnld_recv_frame
  17. nfcmrvl_fw_dnld_abort
  18. nfcmrvl_fw_dnld_start

   1 /*
   2  * Marvell NFC driver: Firmware downloader
   3  *
   4  * Copyright (C) 2015, Marvell International Ltd.
   5  *
   6  * This software file (the "File") is distributed by Marvell International
   7  * Ltd. under the terms of the GNU General Public License Version 2, June 1991
   8  * (the "License").  You may use, redistribute and/or modify this File in
   9  * accordance with the terms and conditions of the License, a copy of which
  10  * is available on the worldwide web at
  11  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  12  *
  13  * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  14  * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  15  * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  16  * this warranty disclaimer.
  17  */
  18 
  19 #include <linux/module.h>
  20 #include <asm/unaligned.h>
  21 #include <linux/firmware.h>
  22 #include <linux/nfc.h>
  23 #include <net/nfc/nci.h>
  24 #include <net/nfc/nci_core.h>
  25 #include "nfcmrvl.h"
  26 
  27 #define FW_DNLD_TIMEOUT                 15000
  28 
  29 #define NCI_OP_PROPRIETARY_BOOT_CMD     nci_opcode_pack(NCI_GID_PROPRIETARY, \
  30                                                         NCI_OP_PROP_BOOT_CMD)
  31 
  32 /* FW download states */
  33 
  34 enum {
  35         STATE_RESET = 0,
  36         STATE_INIT,
  37         STATE_SET_REF_CLOCK,
  38         STATE_SET_HI_CONFIG,
  39         STATE_OPEN_LC,
  40         STATE_FW_DNLD,
  41         STATE_CLOSE_LC,
  42         STATE_BOOT
  43 };
  44 
  45 enum {
  46         SUBSTATE_WAIT_COMMAND = 0,
  47         SUBSTATE_WAIT_ACK_CREDIT,
  48         SUBSTATE_WAIT_NACK_CREDIT,
  49         SUBSTATE_WAIT_DATA_CREDIT,
  50 };
  51 
  52 /*
  53 ** Patterns for responses
  54 */
  55 
  56 static const uint8_t nci_pattern_core_reset_ntf[] = {
  57         0x60, 0x00, 0x02, 0xA0, 0x01
  58 };
  59 
  60 static const uint8_t nci_pattern_core_init_rsp[] = {
  61         0x40, 0x01, 0x11
  62 };
  63 
  64 static const uint8_t nci_pattern_core_set_config_rsp[] = {
  65         0x40, 0x02, 0x02, 0x00, 0x00
  66 };
  67 
  68 static const uint8_t nci_pattern_core_conn_create_rsp[] = {
  69         0x40, 0x04, 0x04, 0x00
  70 };
  71 
  72 static const uint8_t nci_pattern_core_conn_close_rsp[] = {
  73         0x40, 0x05, 0x01, 0x00
  74 };
  75 
  76 static const uint8_t nci_pattern_core_conn_credits_ntf[] = {
  77         0x60, 0x06, 0x03, 0x01, NCI_CORE_LC_CONNID_PROP_FW_DL, 0x01
  78 };
  79 
  80 static const uint8_t nci_pattern_proprietary_boot_rsp[] = {
  81         0x4F, 0x3A, 0x01, 0x00
  82 };
  83 
  84 static struct sk_buff *alloc_lc_skb(struct nfcmrvl_private *priv, uint8_t plen)
  85 {
  86         struct sk_buff *skb;
  87         struct nci_data_hdr *hdr;
  88 
  89         skb = nci_skb_alloc(priv->ndev, (NCI_DATA_HDR_SIZE + plen), GFP_KERNEL);
  90         if (!skb) {
  91                 pr_err("no memory for data\n");
  92                 return NULL;
  93         }
  94 
  95         hdr = skb_put(skb, NCI_DATA_HDR_SIZE);
  96         hdr->conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
  97         hdr->rfu = 0;
  98         hdr->plen = plen;
  99 
 100         nci_mt_set((__u8 *)hdr, NCI_MT_DATA_PKT);
 101         nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
 102 
 103         return skb;
 104 }
 105 
 106 static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error)
 107 {
 108         if (priv->fw_dnld.fw) {
 109                 release_firmware(priv->fw_dnld.fw);
 110                 priv->fw_dnld.fw = NULL;
 111                 priv->fw_dnld.header = NULL;
 112                 priv->fw_dnld.binary_config = NULL;
 113         }
 114 
 115         atomic_set(&priv->ndev->cmd_cnt, 0);
 116 
 117         if (timer_pending(&priv->ndev->cmd_timer))
 118                 del_timer_sync(&priv->ndev->cmd_timer);
 119 
 120         if (timer_pending(&priv->fw_dnld.timer))
 121                 del_timer_sync(&priv->fw_dnld.timer);
 122 
 123         nfc_info(priv->dev, "FW loading over (%d)]\n", error);
 124 
 125         if (error != 0) {
 126                 /* failed, halt the chip to avoid power consumption */
 127                 nfcmrvl_chip_halt(priv);
 128         }
 129 
 130         nfc_fw_download_done(priv->ndev->nfc_dev, priv->fw_dnld.name, error);
 131 }
 132 
 133 static void fw_dnld_timeout(struct timer_list *t)
 134 {
 135         struct nfcmrvl_private *priv = from_timer(priv, t, fw_dnld.timer);
 136 
 137         nfc_err(priv->dev, "FW loading timeout");
 138         priv->fw_dnld.state = STATE_RESET;
 139         fw_dnld_over(priv, -ETIMEDOUT);
 140 }
 141 
 142 static int process_state_reset(struct nfcmrvl_private *priv,
 143                                struct sk_buff *skb)
 144 {
 145         if (sizeof(nci_pattern_core_reset_ntf) != skb->len ||
 146             memcmp(skb->data, nci_pattern_core_reset_ntf,
 147                    sizeof(nci_pattern_core_reset_ntf)))
 148                 return -EINVAL;
 149 
 150         nfc_info(priv->dev, "BootROM reset, start fw download\n");
 151 
 152         /* Start FW download state machine */
 153         priv->fw_dnld.state = STATE_INIT;
 154         nci_send_cmd(priv->ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
 155 
 156         return 0;
 157 }
 158 
 159 static int process_state_init(struct nfcmrvl_private *priv, struct sk_buff *skb)
 160 {
 161         struct nci_core_set_config_cmd cmd;
 162 
 163         if (sizeof(nci_pattern_core_init_rsp) >= skb->len ||
 164             memcmp(skb->data, nci_pattern_core_init_rsp,
 165                    sizeof(nci_pattern_core_init_rsp)))
 166                 return -EINVAL;
 167 
 168         cmd.num_params = 1;
 169         cmd.param.id = NFCMRVL_PROP_REF_CLOCK;
 170         cmd.param.len = 4;
 171         memcpy(cmd.param.val, &priv->fw_dnld.header->ref_clock, 4);
 172 
 173         nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len,
 174                      &cmd);
 175 
 176         priv->fw_dnld.state = STATE_SET_REF_CLOCK;
 177         return 0;
 178 }
 179 
 180 static void create_lc(struct nfcmrvl_private *priv)
 181 {
 182         uint8_t param[2] = { NCI_CORE_LC_PROP_FW_DL, 0x0 };
 183 
 184         priv->fw_dnld.state = STATE_OPEN_LC;
 185         nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, param);
 186 }
 187 
 188 static int process_state_set_ref_clock(struct nfcmrvl_private *priv,
 189                                        struct sk_buff *skb)
 190 {
 191         struct nci_core_set_config_cmd cmd;
 192 
 193         if (sizeof(nci_pattern_core_set_config_rsp) != skb->len ||
 194             memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len))
 195                 return -EINVAL;
 196 
 197         cmd.num_params = 1;
 198         cmd.param.id = NFCMRVL_PROP_SET_HI_CONFIG;
 199 
 200         switch (priv->phy) {
 201         case NFCMRVL_PHY_UART:
 202                 cmd.param.len = 5;
 203                 memcpy(cmd.param.val,
 204                        &priv->fw_dnld.binary_config->uart.baudrate,
 205                        4);
 206                 cmd.param.val[4] =
 207                         priv->fw_dnld.binary_config->uart.flow_control;
 208                 break;
 209         case NFCMRVL_PHY_I2C:
 210                 cmd.param.len = 5;
 211                 memcpy(cmd.param.val,
 212                        &priv->fw_dnld.binary_config->i2c.clk,
 213                        4);
 214                 cmd.param.val[4] = 0;
 215                 break;
 216         case NFCMRVL_PHY_SPI:
 217                 cmd.param.len = 5;
 218                 memcpy(cmd.param.val,
 219                        &priv->fw_dnld.binary_config->spi.clk,
 220                        4);
 221                 cmd.param.val[4] = 0;
 222                 break;
 223         default:
 224                 create_lc(priv);
 225                 return 0;
 226         }
 227 
 228         priv->fw_dnld.state = STATE_SET_HI_CONFIG;
 229         nci_send_cmd(priv->ndev, NCI_OP_CORE_SET_CONFIG_CMD, 3 + cmd.param.len,
 230                      &cmd);
 231         return 0;
 232 }
 233 
 234 static int process_state_set_hi_config(struct nfcmrvl_private *priv,
 235                                        struct sk_buff *skb)
 236 {
 237         if (sizeof(nci_pattern_core_set_config_rsp) != skb->len ||
 238             memcmp(skb->data, nci_pattern_core_set_config_rsp, skb->len))
 239                 return -EINVAL;
 240 
 241         create_lc(priv);
 242         return 0;
 243 }
 244 
 245 static int process_state_open_lc(struct nfcmrvl_private *priv,
 246                                  struct sk_buff *skb)
 247 {
 248         if (sizeof(nci_pattern_core_conn_create_rsp) >= skb->len ||
 249             memcmp(skb->data, nci_pattern_core_conn_create_rsp,
 250                    sizeof(nci_pattern_core_conn_create_rsp)))
 251                 return -EINVAL;
 252 
 253         priv->fw_dnld.state = STATE_FW_DNLD;
 254         priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
 255         priv->fw_dnld.offset = priv->fw_dnld.binary_config->offset;
 256         return 0;
 257 }
 258 
 259 static int process_state_fw_dnld(struct nfcmrvl_private *priv,
 260                                  struct sk_buff *skb)
 261 {
 262         uint16_t len;
 263         uint16_t comp_len;
 264         struct sk_buff *out_skb;
 265 
 266         switch (priv->fw_dnld.substate) {
 267         case SUBSTATE_WAIT_COMMAND:
 268                 /*
 269                  * Command format:
 270                  * B0..2: NCI header
 271                  * B3   : Helper command (0xA5)
 272                  * B4..5: le16 data size
 273                  * B6..7: le16 data size complement (~)
 274                  * B8..N: payload
 275                  */
 276 
 277                 /* Remove NCI HDR */
 278                 skb_pull(skb, 3);
 279                 if (skb->data[0] != HELPER_CMD_PACKET_FORMAT || skb->len != 5) {
 280                         nfc_err(priv->dev, "bad command");
 281                         return -EINVAL;
 282                 }
 283                 skb_pull(skb, 1);
 284                 len = get_unaligned_le16(skb->data);
 285                 skb_pull(skb, 2);
 286                 comp_len = get_unaligned_le16(skb->data);
 287                 memcpy(&comp_len, skb->data, 2);
 288                 skb_pull(skb, 2);
 289                 if (((~len) & 0xFFFF) != comp_len) {
 290                         nfc_err(priv->dev, "bad len complement: %x %x %x",
 291                                 len, comp_len, (~len & 0xFFFF));
 292                         out_skb = alloc_lc_skb(priv, 1);
 293                         if (!out_skb)
 294                                 return -ENOMEM;
 295                         skb_put_u8(out_skb, 0xBF);
 296                         nci_send_frame(priv->ndev, out_skb);
 297                         priv->fw_dnld.substate = SUBSTATE_WAIT_NACK_CREDIT;
 298                         return 0;
 299                 }
 300                 priv->fw_dnld.chunk_len = len;
 301                 out_skb = alloc_lc_skb(priv, 1);
 302                 if (!out_skb)
 303                         return -ENOMEM;
 304                 skb_put_u8(out_skb, HELPER_ACK_PACKET_FORMAT);
 305                 nci_send_frame(priv->ndev, out_skb);
 306                 priv->fw_dnld.substate = SUBSTATE_WAIT_ACK_CREDIT;
 307                 break;
 308 
 309         case SUBSTATE_WAIT_ACK_CREDIT:
 310                 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
 311                     memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
 312                            skb->len)) {
 313                         nfc_err(priv->dev, "bad packet: waiting for credit");
 314                         return -EINVAL;
 315                 }
 316                 if (priv->fw_dnld.chunk_len == 0) {
 317                         /* FW Loading is done */
 318                         uint8_t conn_id = NCI_CORE_LC_CONNID_PROP_FW_DL;
 319 
 320                         priv->fw_dnld.state = STATE_CLOSE_LC;
 321                         nci_send_cmd(priv->ndev, NCI_OP_CORE_CONN_CLOSE_CMD,
 322                                      1, &conn_id);
 323                 } else {
 324                         out_skb = alloc_lc_skb(priv, priv->fw_dnld.chunk_len);
 325                         if (!out_skb)
 326                                 return -ENOMEM;
 327                         skb_put_data(out_skb,
 328                                      ((uint8_t *)priv->fw_dnld.fw->data) + priv->fw_dnld.offset,
 329                                      priv->fw_dnld.chunk_len);
 330                         nci_send_frame(priv->ndev, out_skb);
 331                         priv->fw_dnld.substate = SUBSTATE_WAIT_DATA_CREDIT;
 332                 }
 333                 break;
 334 
 335         case SUBSTATE_WAIT_DATA_CREDIT:
 336                 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
 337                     memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
 338                             skb->len)) {
 339                         nfc_err(priv->dev, "bad packet: waiting for credit");
 340                         return -EINVAL;
 341                 }
 342                 priv->fw_dnld.offset += priv->fw_dnld.chunk_len;
 343                 priv->fw_dnld.chunk_len = 0;
 344                 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
 345                 break;
 346 
 347         case SUBSTATE_WAIT_NACK_CREDIT:
 348                 if (sizeof(nci_pattern_core_conn_credits_ntf) != skb->len ||
 349                     memcmp(nci_pattern_core_conn_credits_ntf, skb->data,
 350                             skb->len)) {
 351                         nfc_err(priv->dev, "bad packet: waiting for credit");
 352                         return -EINVAL;
 353                 }
 354                 priv->fw_dnld.substate = SUBSTATE_WAIT_COMMAND;
 355                 break;
 356         }
 357         return 0;
 358 }
 359 
 360 static int process_state_close_lc(struct nfcmrvl_private *priv,
 361                                   struct sk_buff *skb)
 362 {
 363         if (sizeof(nci_pattern_core_conn_close_rsp) != skb->len ||
 364             memcmp(skb->data, nci_pattern_core_conn_close_rsp, skb->len))
 365                 return -EINVAL;
 366 
 367         priv->fw_dnld.state = STATE_BOOT;
 368         nci_send_cmd(priv->ndev, NCI_OP_PROPRIETARY_BOOT_CMD, 0, NULL);
 369         return 0;
 370 }
 371 
 372 static int process_state_boot(struct nfcmrvl_private *priv, struct sk_buff *skb)
 373 {
 374         if (sizeof(nci_pattern_proprietary_boot_rsp) != skb->len ||
 375             memcmp(skb->data, nci_pattern_proprietary_boot_rsp, skb->len))
 376                 return -EINVAL;
 377 
 378         /*
 379          * Update HI config to use the right configuration for the next
 380          * data exchanges.
 381          */
 382         priv->if_ops->nci_update_config(priv,
 383                                         &priv->fw_dnld.binary_config->config);
 384 
 385         if (priv->fw_dnld.binary_config == &priv->fw_dnld.header->helper) {
 386                 /*
 387                  * This is the case where an helper was needed and we have
 388                  * uploaded it. Now we have to wait the next RESET NTF to start
 389                  * FW download.
 390                  */
 391                 priv->fw_dnld.state = STATE_RESET;
 392                 priv->fw_dnld.binary_config = &priv->fw_dnld.header->firmware;
 393                 nfc_info(priv->dev, "FW loading: helper loaded");
 394         } else {
 395                 nfc_info(priv->dev, "FW loading: firmware loaded");
 396                 fw_dnld_over(priv, 0);
 397         }
 398         return 0;
 399 }
 400 
 401 static void fw_dnld_rx_work(struct work_struct *work)
 402 {
 403         int ret;
 404         struct sk_buff *skb;
 405         struct nfcmrvl_fw_dnld *fw_dnld = container_of(work,
 406                                                        struct nfcmrvl_fw_dnld,
 407                                                        rx_work);
 408         struct nfcmrvl_private *priv = container_of(fw_dnld,
 409                                                     struct nfcmrvl_private,
 410                                                     fw_dnld);
 411 
 412         while ((skb = skb_dequeue(&fw_dnld->rx_q))) {
 413                 nfc_send_to_raw_sock(priv->ndev->nfc_dev, skb,
 414                                      RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
 415                 switch (fw_dnld->state) {
 416                 case STATE_RESET:
 417                         ret = process_state_reset(priv, skb);
 418                         break;
 419                 case STATE_INIT:
 420                         ret = process_state_init(priv, skb);
 421                         break;
 422                 case STATE_SET_REF_CLOCK:
 423                         ret = process_state_set_ref_clock(priv, skb);
 424                         break;
 425                 case STATE_SET_HI_CONFIG:
 426                         ret = process_state_set_hi_config(priv, skb);
 427                         break;
 428                 case STATE_OPEN_LC:
 429                         ret = process_state_open_lc(priv, skb);
 430                         break;
 431                 case STATE_FW_DNLD:
 432                         ret = process_state_fw_dnld(priv, skb);
 433                         break;
 434                 case STATE_CLOSE_LC:
 435                         ret = process_state_close_lc(priv, skb);
 436                         break;
 437                 case STATE_BOOT:
 438                         ret = process_state_boot(priv, skb);
 439                         break;
 440                 default:
 441                         ret = -EFAULT;
 442                 }
 443 
 444                 kfree_skb(skb);
 445 
 446                 if (ret != 0) {
 447                         nfc_err(priv->dev, "FW loading error");
 448                         fw_dnld_over(priv, ret);
 449                         break;
 450                 }
 451         }
 452 }
 453 
 454 int     nfcmrvl_fw_dnld_init(struct nfcmrvl_private *priv)
 455 {
 456         char name[32];
 457 
 458         INIT_WORK(&priv->fw_dnld.rx_work, fw_dnld_rx_work);
 459         snprintf(name, sizeof(name), "%s_nfcmrvl_fw_dnld_rx_wq",
 460                  dev_name(&priv->ndev->nfc_dev->dev));
 461         priv->fw_dnld.rx_wq = create_singlethread_workqueue(name);
 462         if (!priv->fw_dnld.rx_wq)
 463                 return -ENOMEM;
 464         skb_queue_head_init(&priv->fw_dnld.rx_q);
 465         return 0;
 466 }
 467 
 468 void    nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv)
 469 {
 470         destroy_workqueue(priv->fw_dnld.rx_wq);
 471 }
 472 
 473 void    nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
 474                                    struct sk_buff *skb)
 475 {
 476         /* Discard command timer */
 477         if (timer_pending(&priv->ndev->cmd_timer))
 478                 del_timer_sync(&priv->ndev->cmd_timer);
 479 
 480         /* Allow next command */
 481         atomic_set(&priv->ndev->cmd_cnt, 1);
 482 
 483         /* Queue and trigger rx work */
 484         skb_queue_tail(&priv->fw_dnld.rx_q, skb);
 485         queue_work(priv->fw_dnld.rx_wq, &priv->fw_dnld.rx_work);
 486 }
 487 
 488 void nfcmrvl_fw_dnld_abort(struct nfcmrvl_private *priv)
 489 {
 490         fw_dnld_over(priv, -EHOSTDOWN);
 491 }
 492 
 493 int nfcmrvl_fw_dnld_start(struct nci_dev *ndev, const char *firmware_name)
 494 {
 495         struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
 496         struct nfcmrvl_fw_dnld *fw_dnld = &priv->fw_dnld;
 497         int res;
 498 
 499         if (!priv->support_fw_dnld)
 500                 return -ENOTSUPP;
 501 
 502         if (!firmware_name || !firmware_name[0])
 503                 return -EINVAL;
 504 
 505         strcpy(fw_dnld->name, firmware_name);
 506 
 507         /*
 508          * Retrieve FW binary file and parse it to initialize FW download
 509          * state machine.
 510          */
 511 
 512         /* Retrieve FW binary */
 513         res = request_firmware(&fw_dnld->fw, firmware_name,
 514                                &ndev->nfc_dev->dev);
 515         if (res < 0) {
 516                 nfc_err(priv->dev, "failed to retrieve FW %s", firmware_name);
 517                 return -ENOENT;
 518         }
 519 
 520         fw_dnld->header = (const struct nfcmrvl_fw *) priv->fw_dnld.fw->data;
 521 
 522         if (fw_dnld->header->magic != NFCMRVL_FW_MAGIC ||
 523             fw_dnld->header->phy != priv->phy) {
 524                 nfc_err(priv->dev, "bad firmware binary %s magic=0x%x phy=%d",
 525                         firmware_name, fw_dnld->header->magic,
 526                         fw_dnld->header->phy);
 527                 release_firmware(fw_dnld->fw);
 528                 fw_dnld->header = NULL;
 529                 return -EINVAL;
 530         }
 531 
 532         if (fw_dnld->header->helper.offset != 0) {
 533                 nfc_info(priv->dev, "loading helper");
 534                 fw_dnld->binary_config = &fw_dnld->header->helper;
 535         } else {
 536                 nfc_info(priv->dev, "loading firmware");
 537                 fw_dnld->binary_config = &fw_dnld->header->firmware;
 538         }
 539 
 540         /* Configure a timer for timeout */
 541         timer_setup(&priv->fw_dnld.timer, fw_dnld_timeout, 0);
 542         mod_timer(&priv->fw_dnld.timer,
 543                   jiffies + msecs_to_jiffies(FW_DNLD_TIMEOUT));
 544 
 545         /* Ronfigure HI to be sure that it is the bootrom values */
 546         priv->if_ops->nci_update_config(priv,
 547                                         &fw_dnld->header->bootrom.config);
 548 
 549         /* Allow first command */
 550         atomic_set(&priv->ndev->cmd_cnt, 1);
 551 
 552         /* First, reset the chip */
 553         priv->fw_dnld.state = STATE_RESET;
 554         nfcmrvl_chip_reset(priv);
 555 
 556         /* Now wait for CORE_RESET_NTF or timeout */
 557 
 558         return 0;
 559 }

/* [<][>][^][v][top][bottom][index][help] */