1 /* 2 * Generic driver for NXP NCI NFC chips 3 * 4 * Copyright (C) 2014 NXP Semiconductors All rights reserved. 5 * 6 * Authors: Clément Perrochaud <clement.perrochaud@nxp.com> 7 * 8 * Derived from PN544 device driver: 9 * Copyright (C) 2012 Intel Corporation. All rights reserved. 10 * 11 * This program is free software; you can redistribute it and/or modify it 12 * under the terms and conditions of the GNU General Public License, 13 * version 2, as published by the Free Software Foundation. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, see <http://www.gnu.org/licenses/>. 22 */ 23 24 #include <linux/delay.h> 25 #include <linux/gpio.h> 26 #include <linux/module.h> 27 #include <linux/nfc.h> 28 #include <linux/platform_data/nxp-nci.h> 29 30 #include <net/nfc/nci_core.h> 31 32 #include "nxp-nci.h" 33 34 #define NXP_NCI_HDR_LEN 4 35 36 #define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ 37 NFC_PROTO_MIFARE_MASK | \ 38 NFC_PROTO_FELICA_MASK | \ 39 NFC_PROTO_ISO14443_MASK | \ 40 NFC_PROTO_ISO14443_B_MASK | \ 41 NFC_PROTO_NFC_DEP_MASK) 42 43 static int nxp_nci_open(struct nci_dev *ndev) 44 { 45 struct nxp_nci_info *info = nci_get_drvdata(ndev); 46 int r = 0; 47 48 mutex_lock(&info->info_lock); 49 50 if (info->mode != NXP_NCI_MODE_COLD) { 51 r = -EBUSY; 52 goto open_exit; 53 } 54 55 if (info->phy_ops->set_mode) 56 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI); 57 58 info->mode = NXP_NCI_MODE_NCI; 59 60 open_exit: 61 mutex_unlock(&info->info_lock); 62 return r; 63 } 64 65 static int nxp_nci_close(struct nci_dev *ndev) 66 { 67 struct nxp_nci_info *info = nci_get_drvdata(ndev); 68 int r = 0; 69 70 mutex_lock(&info->info_lock); 71 72 if (info->phy_ops->set_mode) 73 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); 74 75 info->mode = NXP_NCI_MODE_COLD; 76 77 mutex_unlock(&info->info_lock); 78 return r; 79 } 80 81 static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 82 { 83 struct nxp_nci_info *info = nci_get_drvdata(ndev); 84 int r; 85 86 if (!info->phy_ops->write) { 87 r = -ENOTSUPP; 88 goto send_exit; 89 } 90 91 if (info->mode != NXP_NCI_MODE_NCI) { 92 r = -EINVAL; 93 goto send_exit; 94 } 95 96 r = info->phy_ops->write(info->phy_id, skb); 97 if (r < 0) 98 kfree_skb(skb); 99 100 send_exit: 101 return r; 102 } 103 104 static struct nci_ops nxp_nci_ops = { 105 .open = nxp_nci_open, 106 .close = nxp_nci_close, 107 .send = nxp_nci_send, 108 .fw_download = nxp_nci_fw_download, 109 }; 110 111 int nxp_nci_probe(void *phy_id, struct device *pdev, 112 const struct nxp_nci_phy_ops *phy_ops, 113 unsigned int max_payload, 114 struct nci_dev **ndev) 115 { 116 struct nxp_nci_info *info; 117 int r; 118 119 info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL); 120 if (!info) { 121 r = -ENOMEM; 122 goto probe_exit; 123 } 124 125 info->phy_id = phy_id; 126 info->pdev = pdev; 127 info->phy_ops = phy_ops; 128 info->max_payload = max_payload; 129 INIT_WORK(&info->fw_info.work, nxp_nci_fw_work); 130 init_completion(&info->fw_info.cmd_completion); 131 mutex_init(&info->info_lock); 132 133 if (info->phy_ops->set_mode) { 134 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); 135 if (r < 0) 136 goto probe_exit; 137 } 138 139 info->mode = NXP_NCI_MODE_COLD; 140 141 info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS, 142 NXP_NCI_HDR_LEN, 0); 143 if (!info->ndev) { 144 r = -ENOMEM; 145 goto probe_exit; 146 } 147 148 nci_set_parent_dev(info->ndev, pdev); 149 nci_set_drvdata(info->ndev, info); 150 r = nci_register_device(info->ndev); 151 if (r < 0) 152 goto probe_exit_free_nci; 153 154 *ndev = info->ndev; 155 156 goto probe_exit; 157 158 probe_exit_free_nci: 159 nci_free_device(info->ndev); 160 probe_exit: 161 return r; 162 } 163 EXPORT_SYMBOL(nxp_nci_probe); 164 165 void nxp_nci_remove(struct nci_dev *ndev) 166 { 167 struct nxp_nci_info *info = nci_get_drvdata(ndev); 168 169 if (info->mode == NXP_NCI_MODE_FW) 170 nxp_nci_fw_work_complete(info, -ESHUTDOWN); 171 cancel_work_sync(&info->fw_info.work); 172 173 mutex_lock(&info->info_lock); 174 175 if (info->phy_ops->set_mode) 176 info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD); 177 178 nci_unregister_device(ndev); 179 nci_free_device(ndev); 180 181 mutex_unlock(&info->info_lock); 182 } 183 EXPORT_SYMBOL(nxp_nci_remove); 184 185 MODULE_LICENSE("GPL"); 186 MODULE_DESCRIPTION("NXP NCI NFC driver"); 187 MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>"); 188