Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Generic driver for NXP NCI NFC chips
0004  *
0005  * Copyright (C) 2014  NXP Semiconductors  All rights reserved.
0006  *
0007  * Authors: Clément Perrochaud <clement.perrochaud@nxp.com>
0008  *
0009  * Derived from PN544 device driver:
0010  * Copyright (C) 2012  Intel Corporation. All rights reserved.
0011  */
0012 
0013 #include <linux/delay.h>
0014 #include <linux/module.h>
0015 #include <linux/nfc.h>
0016 
0017 #include <net/nfc/nci_core.h>
0018 
0019 #include "nxp-nci.h"
0020 
0021 #define NXP_NCI_HDR_LEN 4
0022 
0023 #define NXP_NCI_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
0024                    NFC_PROTO_MIFARE_MASK | \
0025                    NFC_PROTO_FELICA_MASK | \
0026                    NFC_PROTO_ISO14443_MASK | \
0027                    NFC_PROTO_ISO14443_B_MASK | \
0028                    NFC_PROTO_NFC_DEP_MASK)
0029 
0030 #define NXP_NCI_RF_PLL_UNLOCKED_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x21)
0031 #define NXP_NCI_RF_TXLDO_ERROR_NTF nci_opcode_pack(NCI_GID_RF_MGMT, 0x23)
0032 
0033 static int nxp_nci_open(struct nci_dev *ndev)
0034 {
0035     struct nxp_nci_info *info = nci_get_drvdata(ndev);
0036     int r = 0;
0037 
0038     mutex_lock(&info->info_lock);
0039 
0040     if (info->mode != NXP_NCI_MODE_COLD) {
0041         r = -EBUSY;
0042         goto open_exit;
0043     }
0044 
0045     if (info->phy_ops->set_mode)
0046         r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_NCI);
0047 
0048     info->mode = NXP_NCI_MODE_NCI;
0049 
0050 open_exit:
0051     mutex_unlock(&info->info_lock);
0052     return r;
0053 }
0054 
0055 static int nxp_nci_close(struct nci_dev *ndev)
0056 {
0057     struct nxp_nci_info *info = nci_get_drvdata(ndev);
0058     int r = 0;
0059 
0060     mutex_lock(&info->info_lock);
0061 
0062     if (info->phy_ops->set_mode)
0063         r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
0064 
0065     info->mode = NXP_NCI_MODE_COLD;
0066 
0067     mutex_unlock(&info->info_lock);
0068     return r;
0069 }
0070 
0071 static int nxp_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
0072 {
0073     struct nxp_nci_info *info = nci_get_drvdata(ndev);
0074     int r;
0075 
0076     if (!info->phy_ops->write)
0077         return -EOPNOTSUPP;
0078 
0079     if (info->mode != NXP_NCI_MODE_NCI)
0080         return -EINVAL;
0081 
0082     r = info->phy_ops->write(info->phy_id, skb);
0083     if (r < 0)
0084         kfree_skb(skb);
0085 
0086     return r;
0087 }
0088 
0089 static int nxp_nci_rf_pll_unlocked_ntf(struct nci_dev *ndev,
0090                        struct sk_buff *skb)
0091 {
0092     nfc_err(&ndev->nfc_dev->dev,
0093         "PLL didn't lock. Missing or unstable clock?\n");
0094 
0095     return 0;
0096 }
0097 
0098 static int nxp_nci_rf_txldo_error_ntf(struct nci_dev *ndev,
0099                       struct sk_buff *skb)
0100 {
0101     nfc_err(&ndev->nfc_dev->dev,
0102         "RF transmitter couldn't start. Bad power and/or configuration?\n");
0103 
0104     return 0;
0105 }
0106 
0107 static const struct nci_driver_ops nxp_nci_core_ops[] = {
0108     {
0109         .opcode = NXP_NCI_RF_PLL_UNLOCKED_NTF,
0110         .ntf = nxp_nci_rf_pll_unlocked_ntf,
0111     },
0112     {
0113         .opcode = NXP_NCI_RF_TXLDO_ERROR_NTF,
0114         .ntf = nxp_nci_rf_txldo_error_ntf,
0115     },
0116 };
0117 
0118 static const struct nci_ops nxp_nci_ops = {
0119     .open = nxp_nci_open,
0120     .close = nxp_nci_close,
0121     .send = nxp_nci_send,
0122     .fw_download = nxp_nci_fw_download,
0123     .core_ops = nxp_nci_core_ops,
0124     .n_core_ops = ARRAY_SIZE(nxp_nci_core_ops),
0125 };
0126 
0127 int nxp_nci_probe(void *phy_id, struct device *pdev,
0128           const struct nxp_nci_phy_ops *phy_ops,
0129           unsigned int max_payload,
0130           struct nci_dev **ndev)
0131 {
0132     struct nxp_nci_info *info;
0133     int r;
0134 
0135     info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
0136     if (!info)
0137         return -ENOMEM;
0138 
0139     info->phy_id = phy_id;
0140     info->pdev = pdev;
0141     info->phy_ops = phy_ops;
0142     info->max_payload = max_payload;
0143     INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
0144     init_completion(&info->fw_info.cmd_completion);
0145     mutex_init(&info->info_lock);
0146 
0147     if (info->phy_ops->set_mode) {
0148         r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
0149         if (r < 0)
0150             return r;
0151     }
0152 
0153     info->mode = NXP_NCI_MODE_COLD;
0154 
0155     info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
0156                      NXP_NCI_HDR_LEN, 0);
0157     if (!info->ndev)
0158         return -ENOMEM;
0159 
0160     nci_set_parent_dev(info->ndev, pdev);
0161     nci_set_drvdata(info->ndev, info);
0162     r = nci_register_device(info->ndev);
0163     if (r < 0) {
0164         nci_free_device(info->ndev);
0165         return r;
0166     }
0167 
0168     *ndev = info->ndev;
0169     return r;
0170 }
0171 EXPORT_SYMBOL(nxp_nci_probe);
0172 
0173 void nxp_nci_remove(struct nci_dev *ndev)
0174 {
0175     struct nxp_nci_info *info = nci_get_drvdata(ndev);
0176 
0177     if (info->mode == NXP_NCI_MODE_FW)
0178         nxp_nci_fw_work_complete(info, -ESHUTDOWN);
0179     cancel_work_sync(&info->fw_info.work);
0180 
0181     mutex_lock(&info->info_lock);
0182 
0183     if (info->phy_ops->set_mode)
0184         info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
0185 
0186     nci_unregister_device(ndev);
0187     nci_free_device(ndev);
0188 
0189     mutex_unlock(&info->info_lock);
0190 }
0191 EXPORT_SYMBOL(nxp_nci_remove);
0192 
0193 MODULE_LICENSE("GPL");
0194 MODULE_DESCRIPTION("NXP NCI NFC driver");
0195 MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");