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>"); 175