GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / nfc / nxp-nci / core.c
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                 return -EOPNOTSUPP;
75
76         if (info->mode != NXP_NCI_MODE_NCI)
77                 return -EINVAL;
78
79         r = info->phy_ops->write(info->phy_id, skb);
80         if (r < 0) {
81                 kfree_skb(skb);
82                 return r;
83         }
84
85         consume_skb(skb);
86         return 0;
87 }
88
89 static struct nci_ops nxp_nci_ops = {
90         .open = nxp_nci_open,
91         .close = nxp_nci_close,
92         .send = nxp_nci_send,
93         .fw_download = nxp_nci_fw_download,
94 };
95
96 int nxp_nci_probe(void *phy_id, struct device *pdev,
97                   const struct nxp_nci_phy_ops *phy_ops,
98                   unsigned int max_payload,
99                   struct nci_dev **ndev)
100 {
101         struct nxp_nci_info *info;
102         int r;
103
104         info = devm_kzalloc(pdev, sizeof(struct nxp_nci_info), GFP_KERNEL);
105         if (!info)
106                 return -ENOMEM;
107
108         info->phy_id = phy_id;
109         info->pdev = pdev;
110         info->phy_ops = phy_ops;
111         info->max_payload = max_payload;
112         INIT_WORK(&info->fw_info.work, nxp_nci_fw_work);
113         init_completion(&info->fw_info.cmd_completion);
114         mutex_init(&info->info_lock);
115
116         if (info->phy_ops->set_mode) {
117                 r = info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
118                 if (r < 0)
119                         return r;
120         }
121
122         info->mode = NXP_NCI_MODE_COLD;
123
124         info->ndev = nci_allocate_device(&nxp_nci_ops, NXP_NCI_NFC_PROTOCOLS,
125                                          NXP_NCI_HDR_LEN, 0);
126         if (!info->ndev)
127                 return -ENOMEM;
128
129         nci_set_parent_dev(info->ndev, pdev);
130         nci_set_drvdata(info->ndev, info);
131         r = nci_register_device(info->ndev);
132         if (r < 0) {
133                 nci_free_device(info->ndev);
134                 return r;
135         }
136
137         *ndev = info->ndev;
138         return r;
139 }
140 EXPORT_SYMBOL(nxp_nci_probe);
141
142 void nxp_nci_remove(struct nci_dev *ndev)
143 {
144         struct nxp_nci_info *info = nci_get_drvdata(ndev);
145
146         if (info->mode == NXP_NCI_MODE_FW)
147                 nxp_nci_fw_work_complete(info, -ESHUTDOWN);
148         cancel_work_sync(&info->fw_info.work);
149
150         mutex_lock(&info->info_lock);
151
152         if (info->phy_ops->set_mode)
153                 info->phy_ops->set_mode(info->phy_id, NXP_NCI_MODE_COLD);
154
155         nci_unregister_device(ndev);
156         nci_free_device(ndev);
157
158         mutex_unlock(&info->info_lock);
159 }
160 EXPORT_SYMBOL(nxp_nci_remove);
161
162 MODULE_LICENSE("GPL");
163 MODULE_DESCRIPTION("NXP NCI NFC driver");
164 MODULE_AUTHOR("Clément Perrochaud <clement.perrochaud@nxp.com>");