root/drivers/nfc/nxp-nci/core.c

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

DEFINITIONS

This source file includes following definitions.
  1. nxp_nci_open
  2. nxp_nci_close
  3. nxp_nci_send
  4. nxp_nci_probe
  5. nxp_nci_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Generic driver for NXP NCI NFC chips
   4  *
   5  * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
   6  *
   7  * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
   8  *
   9  * Derived from PN544 device driver:
  10  * Copyright (C) 2012  Intel Corporation. All rights reserved.
  11  */
  12 
  13 #include <linux/delay.h>
  14 #include <linux/module.h>
  15 #include <linux/nfc.h>
  16 
  17 #include <net/nfc/nci_core.h>
  18 
  19 #include "nxp-nci.h"
  20 
  21 #define NXP_NCI_HDR_LEN 4
  22 
  23 #define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
  24                                NFC_PROTO_MIFARE_MASK | \
  25                                NFC_PROTO_FELICA_MASK | \
  26                                NFC_PROTO_ISO14443_MASK | \
  27                                NFC_PROTO_ISO14443_B_MASK | \
  28                                NFC_PROTO_NFC_DEP_MASK)
  29 
  30 static int nxp_nci_open(struct nci_dev *ndev)
  31 {
  32         struct nxp_nci_info *info = nci_get_drvdata(ndev);
  33         int r = 0;
  34 
  35         mutex_lock(&info->info_lock);
  36 
  37         if (info->mode != NXP_NCI_MODE_COLD) {
  38                 r = -EBUSY;
  39                 goto open_exit;
  40         }
  41 
  42         if (info->phy_ops->set_mode)
  43                 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI);
  44 
  45         info->mode = NXP_NCI_MODE_NCI;
  46 
  47 open_exit:
  48         mutex_unlock(&info->info_lock);
  49         return r;
  50 }
  51 
  52 static int nxp_nci_close(struct nci_dev *ndev)
  53 {
  54         struct nxp_nci_info *info = nci_get_drvdata(ndev);
  55         int r = 0;
  56 
  57         mutex_lock(&info->info_lock);
  58 
  59         if (info->phy_ops->set_mode)
  60                 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
  61 
  62         info->mode = NXP_NCI_MODE_COLD;
  63 
  64         mutex_unlock(&info->info_lock);
  65         return r;
  66 }
  67 
  68 static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
  69 {
  70         struct nxp_nci_info *info = nci_get_drvdata(ndev);
  71         int r;
  72 
  73         if (!info->phy_ops->write) {
  74                 r = -ENOTSUPP;
  75                 goto send_exit;
  76         }
  77 
  78         if (info->mode != NXP_NCI_MODE_NCI) {
  79                 r = -EINVAL;
  80                 goto send_exit;
  81         }
  82 
  83         r = info->phy_ops->write(info->phy_id, skb);
  84         if (r < 0)
  85                 kfree_skb(skb);
  86 
  87 send_exit:
  88         return r;
  89 }
  90 
  91 static struct nci_ops nxp_nci_ops = {
  92         .open = nxp_nci_open,
  93         .close = nxp_nci_close,
  94         .send = nxp_nci_send,
  95         .fw_download = nxp_nci_fw_download,
  96 };
  97 
  98 int nxp_nci_probe(void *phy_id, struct device *pdev,
  99                   const struct nxp_nci_phy_ops *phy_ops,
 100                   unsigned int max_payload,
 101                   struct nci_dev **ndev)
 102 {
 103         struct nxp_nci_info *info;
 104         int r;
 105 
 106         info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
 107         if (!info) {
 108                 r = -ENOMEM;
 109                 goto probe_exit;
 110         }
 111 
 112         info->phy_id = phy_id;
 113         info->pdev = pdev;
 114         info->phy_ops = phy_ops;
 115         info->max_payload = max_payload;
 116         INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
 117         init_completion(&info->fw_info.cmd_completion);
 118         mutex_init(&info->info_lock);
 119 
 120         if (info->phy_ops->set_mode) {
 121                 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
 122                 if (r < 0)
 123                         goto probe_exit;
 124         }
 125 
 126         info->mode = NXP_NCI_MODE_COLD;
 127 
 128         info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
 129                                          NXP_NCI_HDR_LEN, 0);
 130         if (!info->ndev) {
 131                 r = -ENOMEM;
 132                 goto probe_exit;
 133         }
 134 
 135         nci_set_parent_dev(info->ndev, pdev);
 136         nci_set_drvdata(info->ndev, info);
 137         r = nci_register_device(info->ndev);
 138         if (r < 0)
 139                 goto probe_exit_free_nci;
 140 
 141         *ndev = info->ndev;
 142 
 143         goto probe_exit;
 144 
 145 probe_exit_free_nci:
 146         nci_free_device(info->ndev);
 147 probe_exit:
 148         return r;
 149 }
 150 EXPORT_SYMBOL(nxp_nci_probe);
 151 
 152 void nxp_nci_remove(struct nci_dev *ndev)
 153 {
 154         struct nxp_nci_info *info = nci_get_drvdata(ndev);
 155 
 156         if (info->mode == NXP_NCI_MODE_FW)
 157                 nxp_nci_fw_work_complete(info, -ESHUTDOWN);
 158         cancel_work_sync(&info->fw_info.work);
 159 
 160         mutex_lock(&info->info_lock);
 161 
 162         if (info->phy_ops->set_mode)
 163                 info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
 164 
 165         nci_unregister_device(ndev);
 166         nci_free_device(ndev);
 167 
 168         mutex_unlock(&info->info_lock);
 169 }
 170 EXPORT_SYMBOL(nxp_nci_remove);
 171 
 172 MODULE_LICENSE("GPL");
 173 MODULE_DESCRIPTION("NXP NCI NFC driver");
 174 MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");

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