aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/nfc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-09-03 11:08:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2015-09-03 11:08:17 -0400
commitdd5cdb48edfd34401799056a9acf61078d773f90 (patch)
tree8e251fb4a4c196540fe9b6a6d8b13275f93a057c /drivers/nfc
parent1e1a4e8f439113b7820bc7150569f685e1cc2b43 (diff)
parent62da98656b62a5ca57f22263705175af8ded5aa1 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next
Pull networking updates from David Miller: "Another merge window, another set of networking changes. I've heard rumblings that the lightweight tunnels infrastructure has been voted networking change of the year. But what do I know? 1) Add conntrack support to openvswitch, from Joe Stringer. 2) Initial support for VRF (Virtual Routing and Forwarding), which allows the segmentation of routing paths without using multiple devices. There are some semantic kinks to work out still, but this is a reasonably strong foundation. From David Ahern. 3) Remove spinlock fro act_bpf fast path, from Alexei Starovoitov. 4) Ignore route nexthops with a link down state in ipv6, just like ipv4. From Andy Gospodarek. 5) Remove spinlock from fast path of act_gact and act_mirred, from Eric Dumazet. 6) Document the DSA layer, from Florian Fainelli. 7) Add netconsole support to bcmgenet, systemport, and DSA. Also from Florian Fainelli. 8) Add Mellanox Switch Driver and core infrastructure, from Jiri Pirko. 9) Add support for "light weight tunnels", which allow for encapsulation and decapsulation without bearing the overhead of a full blown netdevice. From Thomas Graf, Jiri Benc, and a cast of others. 10) Add Identifier Locator Addressing support for ipv6, from Tom Herbert. 11) Support fragmented SKBs in iwlwifi, from Johannes Berg. 12) Allow perf PMUs to be accessed from eBPF programs, from Kaixu Xia. 13) Add BQL support to 3c59x driver, from Loganaden Velvindron. 14) Stop using a zero TX queue length to mean that a device shouldn't have a qdisc attached, use an explicit flag instead. From Phil Sutter. 15) Use generic geneve netdevice infrastructure in openvswitch, from Pravin B Shelar. 16) Add infrastructure to avoid re-forwarding a packet in software that was already forwarded by a hardware switch. From Scott Feldman. 17) Allow AF_PACKET fanout function to be implemented in a bpf program, from Willem de Bruijn" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next: (1458 commits) netfilter: nf_conntrack: make nf_ct_zone_dflt built-in netfilter: nf_dup{4, 6}: fix build error when nf_conntrack disabled net: fec: clear receive interrupts before processing a packet ipv6: fix exthdrs offload registration in out_rt path xen-netback: add support for multicast control bgmac: Update fixed_phy_register() sock, diag: fix panic in sock_diag_put_filterinfo flow_dissector: Use 'const' where possible. flow_dissector: Fix function argument ordering dependency ixgbe: Resolve "initialized field overwritten" warnings ixgbe: Remove bimodal SR-IOV disabling ixgbe: Add support for reporting 2.5G link speed ixgbe: fix bounds checking in ixgbe_setup_tc for 82598 ixgbe: support for ethtool set_rxfh ixgbe: Avoid needless PHY access on copper phys ixgbe: cleanup to use cached mask value ixgbe: Remove second instance of lan_id variable ixgbe: use kzalloc for allocating one thing flow: Move __get_hash_from_flowi{4,6} into flow_dissector.c ixgbe: Remove unused PCI bus types ...
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/Kconfig1
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/s3fwrn5/Kconfig19
-rw-r--r--drivers/nfc/s3fwrn5/Makefile11
-rw-r--r--drivers/nfc/s3fwrn5/core.c219
-rw-r--r--drivers/nfc/s3fwrn5/firmware.c511
-rw-r--r--drivers/nfc/s3fwrn5/firmware.h111
-rw-r--r--drivers/nfc/s3fwrn5/i2c.c306
-rw-r--r--drivers/nfc/s3fwrn5/nci.c165
-rw-r--r--drivers/nfc/s3fwrn5/nci.h89
-rw-r--r--drivers/nfc/s3fwrn5/s3fwrn5.h99
-rw-r--r--drivers/nfc/st-nci/Kconfig11
-rw-r--r--drivers/nfc/st-nci/Makefile3
-rw-r--r--drivers/nfc/st-nci/i2c.c23
-rw-r--r--drivers/nfc/st-nci/ndlc.c7
-rw-r--r--drivers/nfc/st-nci/spi.c392
-rw-r--r--drivers/nfc/st-nci/st-nci_se.c8
-rw-r--r--drivers/nfc/st21nfca/st21nfca.c11
-rw-r--r--drivers/nfc/trf7970a.c6
19 files changed, 1966 insertions, 27 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 722673cb785b..6639cd1cae36 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -74,4 +74,5 @@ source "drivers/nfc/nfcmrvl/Kconfig"
74source "drivers/nfc/st21nfca/Kconfig" 74source "drivers/nfc/st21nfca/Kconfig"
75source "drivers/nfc/st-nci/Kconfig" 75source "drivers/nfc/st-nci/Kconfig"
76source "drivers/nfc/nxp-nci/Kconfig" 76source "drivers/nfc/nxp-nci/Kconfig"
77source "drivers/nfc/s3fwrn5/Kconfig"
77endmenu 78endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 368b6dfe71b3..2757fe1b8aa5 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
14obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ 14obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
15obj-$(CONFIG_NFC_ST_NCI) += st-nci/ 15obj-$(CONFIG_NFC_ST_NCI) += st-nci/
16obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ 16obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
17obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/
diff --git a/drivers/nfc/s3fwrn5/Kconfig b/drivers/nfc/s3fwrn5/Kconfig
new file mode 100644
index 000000000000..7e3b255b3f99
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/Kconfig
@@ -0,0 +1,19 @@
1config NFC_S3FWRN5
2 tristate
3 ---help---
4 Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities
5 of chip. It's intended to be used by PHYs to avoid duplicating lots
6 of common code.
7
8config NFC_S3FWRN5_I2C
9 tristate "Samsung S3FWRN5 I2C support"
10 depends on NFC_NCI && I2C
11 select NFC_S3FWRN5
12 default n
13 ---help---
14 This module adds support for an I2C interface to the S3FWRN5 chip.
15 Select this if your platform is using the I2C bus.
16
17 To compile this driver as a module, choose m here. The module will
18 be called s3fwrn5_i2c.ko.
19 Say N if unsure.
diff --git a/drivers/nfc/s3fwrn5/Makefile b/drivers/nfc/s3fwrn5/Makefile
new file mode 100644
index 000000000000..3381c34faf62
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/Makefile
@@ -0,0 +1,11 @@
1#
2# Makefile for Samsung S3FWRN5 NFC driver
3#
4
5s3fwrn5-objs = core.o firmware.o nci.o
6s3fwrn5_i2c-objs = i2c.o
7
8obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5.o
9obj-$(CONFIG_NFC_S3FWRN5_I2C) += s3fwrn5_i2c.o
10
11ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/s3fwrn5/core.c b/drivers/nfc/s3fwrn5/core.c
new file mode 100644
index 000000000000..0d866ca295e3
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/core.c
@@ -0,0 +1,219 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/module.h>
21#include <net/nfc/nci_core.h>
22
23#include "s3fwrn5.h"
24#include "firmware.h"
25#include "nci.h"
26
27#define S3FWRN5_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
28 NFC_PROTO_MIFARE_MASK | \
29 NFC_PROTO_FELICA_MASK | \
30 NFC_PROTO_ISO14443_MASK | \
31 NFC_PROTO_ISO14443_B_MASK | \
32 NFC_PROTO_ISO15693_MASK)
33
34static int s3fwrn5_firmware_update(struct s3fwrn5_info *info)
35{
36 bool need_update;
37 int ret;
38
39 s3fwrn5_fw_init(&info->fw_info, "sec_s3fwrn5_firmware.bin");
40
41 /* Update firmware */
42
43 s3fwrn5_set_wake(info, false);
44 s3fwrn5_set_mode(info, S3FWRN5_MODE_FW);
45
46 ret = s3fwrn5_fw_setup(&info->fw_info);
47 if (ret < 0)
48 return ret;
49
50 need_update = s3fwrn5_fw_check_version(&info->fw_info,
51 info->ndev->manufact_specific_info);
52 if (!need_update)
53 goto out;
54
55 dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n");
56
57 ret = s3fwrn5_fw_download(&info->fw_info);
58 if (ret < 0)
59 goto out;
60
61 /* Update RF configuration */
62
63 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
64
65 s3fwrn5_set_wake(info, true);
66 ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin");
67 s3fwrn5_set_wake(info, false);
68
69out:
70 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
71 s3fwrn5_fw_cleanup(&info->fw_info);
72 return ret;
73}
74
75static int s3fwrn5_nci_open(struct nci_dev *ndev)
76{
77 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
78
79 if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD)
80 return -EBUSY;
81
82 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
83 s3fwrn5_set_wake(info, true);
84
85 return 0;
86}
87
88static int s3fwrn5_nci_close(struct nci_dev *ndev)
89{
90 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
91
92 s3fwrn5_set_wake(info, false);
93 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
94
95 return 0;
96}
97
98static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
99{
100 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
101 int ret;
102
103 mutex_lock(&info->mutex);
104
105 if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) {
106 mutex_unlock(&info->mutex);
107 return -EINVAL;
108 }
109
110 ret = s3fwrn5_write(info, skb);
111 if (ret < 0)
112 kfree_skb(skb);
113
114 mutex_unlock(&info->mutex);
115 return ret;
116}
117
118static int s3fwrn5_nci_post_setup(struct nci_dev *ndev)
119{
120 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
121 int ret;
122
123 ret = s3fwrn5_firmware_update(info);
124 if (ret < 0)
125 goto out;
126
127 /* NCI core reset */
128
129 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
130 s3fwrn5_set_wake(info, true);
131
132 ret = nci_core_reset(info->ndev);
133 if (ret < 0)
134 goto out;
135
136 ret = nci_core_init(info->ndev);
137
138out:
139 return ret;
140}
141
142static struct nci_ops s3fwrn5_nci_ops = {
143 .open = s3fwrn5_nci_open,
144 .close = s3fwrn5_nci_close,
145 .send = s3fwrn5_nci_send,
146 .post_setup = s3fwrn5_nci_post_setup,
147};
148
149int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
150 struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload)
151{
152 struct s3fwrn5_info *info;
153 int ret;
154
155 info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL);
156 if (!info)
157 return -ENOMEM;
158
159 info->phy_id = phy_id;
160 info->pdev = pdev;
161 info->phy_ops = phy_ops;
162 info->max_payload = max_payload;
163 mutex_init(&info->mutex);
164
165 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
166
167 s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops.prop_ops,
168 &s3fwrn5_nci_ops.n_prop_ops);
169
170 info->ndev = nci_allocate_device(&s3fwrn5_nci_ops,
171 S3FWRN5_NFC_PROTOCOLS, 0, 0);
172 if (!info->ndev)
173 return -ENOMEM;
174
175 nci_set_parent_dev(info->ndev, pdev);
176 nci_set_drvdata(info->ndev, info);
177
178 ret = nci_register_device(info->ndev);
179 if (ret < 0) {
180 nci_free_device(info->ndev);
181 return ret;
182 }
183
184 info->fw_info.ndev = info->ndev;
185
186 *ndev = info->ndev;
187
188 return ret;
189}
190EXPORT_SYMBOL(s3fwrn5_probe);
191
192void s3fwrn5_remove(struct nci_dev *ndev)
193{
194 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
195
196 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
197
198 nci_unregister_device(ndev);
199 nci_free_device(ndev);
200}
201EXPORT_SYMBOL(s3fwrn5_remove);
202
203int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,
204 enum s3fwrn5_mode mode)
205{
206 switch (mode) {
207 case S3FWRN5_MODE_NCI:
208 return nci_recv_frame(ndev, skb);
209 case S3FWRN5_MODE_FW:
210 return s3fwrn5_fw_recv_frame(ndev, skb);
211 default:
212 return -ENODEV;
213 }
214}
215EXPORT_SYMBOL(s3fwrn5_recv_frame);
216
217MODULE_LICENSE("GPL");
218MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
219MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");
diff --git a/drivers/nfc/s3fwrn5/firmware.c b/drivers/nfc/s3fwrn5/firmware.c
new file mode 100644
index 000000000000..64a90252c57f
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/firmware.c
@@ -0,0 +1,511 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/completion.h>
21#include <linux/firmware.h>
22#include <linux/crypto.h>
23#include <crypto/sha.h>
24
25#include "s3fwrn5.h"
26#include "firmware.h"
27
28struct s3fwrn5_fw_version {
29 __u8 major;
30 __u8 build1;
31 __u8 build2;
32 __u8 target;
33};
34
35static int s3fwrn5_fw_send_msg(struct s3fwrn5_fw_info *fw_info,
36 struct sk_buff *msg, struct sk_buff **rsp)
37{
38 struct s3fwrn5_info *info =
39 container_of(fw_info, struct s3fwrn5_info, fw_info);
40 long ret;
41
42 reinit_completion(&fw_info->completion);
43
44 ret = s3fwrn5_write(info, msg);
45 if (ret < 0)
46 return ret;
47
48 ret = wait_for_completion_interruptible_timeout(
49 &fw_info->completion, msecs_to_jiffies(1000));
50 if (ret < 0)
51 return ret;
52 else if (ret == 0)
53 return -ENXIO;
54
55 if (!fw_info->rsp)
56 return -EINVAL;
57
58 *rsp = fw_info->rsp;
59 fw_info->rsp = NULL;
60
61 return 0;
62}
63
64static int s3fwrn5_fw_prep_msg(struct s3fwrn5_fw_info *fw_info,
65 struct sk_buff **msg, u8 type, u8 code, const void *data, u16 len)
66{
67 struct s3fwrn5_fw_header hdr;
68 struct sk_buff *skb;
69
70 hdr.type = type | fw_info->parity;
71 fw_info->parity ^= 0x80;
72 hdr.code = code;
73 hdr.len = len;
74
75 skb = alloc_skb(S3FWRN5_FW_HDR_SIZE + len, GFP_KERNEL);
76 if (!skb)
77 return -ENOMEM;
78
79 memcpy(skb_put(skb, S3FWRN5_FW_HDR_SIZE), &hdr, S3FWRN5_FW_HDR_SIZE);
80 if (len)
81 memcpy(skb_put(skb, len), data, len);
82
83 *msg = skb;
84
85 return 0;
86}
87
88static int s3fwrn5_fw_get_bootinfo(struct s3fwrn5_fw_info *fw_info,
89 struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
90{
91 struct sk_buff *msg, *rsp = NULL;
92 struct s3fwrn5_fw_header *hdr;
93 int ret;
94
95 /* Send GET_BOOTINFO command */
96
97 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
98 S3FWRN5_FW_CMD_GET_BOOTINFO, NULL, 0);
99 if (ret < 0)
100 return ret;
101
102 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
103 kfree_skb(msg);
104 if (ret < 0)
105 return ret;
106
107 hdr = (struct s3fwrn5_fw_header *) rsp->data;
108 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
109 ret = -EINVAL;
110 goto out;
111 }
112
113 memcpy(bootinfo, rsp->data + S3FWRN5_FW_HDR_SIZE, 10);
114
115out:
116 kfree_skb(rsp);
117 return ret;
118}
119
120static int s3fwrn5_fw_enter_update_mode(struct s3fwrn5_fw_info *fw_info,
121 const void *hash_data, u16 hash_size,
122 const void *sig_data, u16 sig_size)
123{
124 struct s3fwrn5_fw_cmd_enter_updatemode args;
125 struct sk_buff *msg, *rsp = NULL;
126 struct s3fwrn5_fw_header *hdr;
127 int ret;
128
129 /* Send ENTER_UPDATE_MODE command */
130
131 args.hashcode_size = hash_size;
132 args.signature_size = sig_size;
133
134 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
135 S3FWRN5_FW_CMD_ENTER_UPDATE_MODE, &args, sizeof(args));
136 if (ret < 0)
137 return ret;
138
139 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
140 kfree_skb(msg);
141 if (ret < 0)
142 return ret;
143
144 hdr = (struct s3fwrn5_fw_header *) rsp->data;
145 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
146 ret = -EPROTO;
147 goto out;
148 }
149
150 kfree_skb(rsp);
151
152 /* Send hashcode data */
153
154 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
155 hash_data, hash_size);
156 if (ret < 0)
157 return ret;
158
159 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
160 kfree_skb(msg);
161 if (ret < 0)
162 return ret;
163
164 hdr = (struct s3fwrn5_fw_header *) rsp->data;
165 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
166 ret = -EPROTO;
167 goto out;
168 }
169
170 kfree_skb(rsp);
171
172 /* Send signature data */
173
174 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_DATA, 0,
175 sig_data, sig_size);
176 if (ret < 0)
177 return ret;
178
179 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
180 kfree_skb(msg);
181 if (ret < 0)
182 return ret;
183
184 hdr = (struct s3fwrn5_fw_header *) rsp->data;
185 if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
186 ret = -EPROTO;
187
188out:
189 kfree_skb(rsp);
190 return ret;
191}
192
193static int s3fwrn5_fw_update_sector(struct s3fwrn5_fw_info *fw_info,
194 u32 base_addr, const void *data)
195{
196 struct s3fwrn5_fw_cmd_update_sector args;
197 struct sk_buff *msg, *rsp = NULL;
198 struct s3fwrn5_fw_header *hdr;
199 int ret, i;
200
201 /* Send UPDATE_SECTOR command */
202
203 args.base_address = base_addr;
204
205 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
206 S3FWRN5_FW_CMD_UPDATE_SECTOR, &args, sizeof(args));
207 if (ret < 0)
208 return ret;
209
210 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
211 kfree_skb(msg);
212 if (ret < 0)
213 return ret;
214
215 hdr = (struct s3fwrn5_fw_header *) rsp->data;
216 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
217 ret = -EPROTO;
218 goto err;
219 }
220
221 kfree_skb(rsp);
222
223 /* Send data split into 256-byte packets */
224
225 for (i = 0; i < 16; ++i) {
226 ret = s3fwrn5_fw_prep_msg(fw_info, &msg,
227 S3FWRN5_FW_MSG_DATA, 0, data+256*i, 256);
228 if (ret < 0)
229 break;
230
231 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
232 kfree_skb(msg);
233 if (ret < 0)
234 break;
235
236 hdr = (struct s3fwrn5_fw_header *) rsp->data;
237 if (hdr->code != S3FWRN5_FW_RET_SUCCESS) {
238 ret = -EPROTO;
239 goto err;
240 }
241
242 kfree_skb(rsp);
243 }
244
245 return ret;
246
247err:
248 kfree_skb(rsp);
249 return ret;
250}
251
252static int s3fwrn5_fw_complete_update_mode(struct s3fwrn5_fw_info *fw_info)
253{
254 struct sk_buff *msg, *rsp = NULL;
255 struct s3fwrn5_fw_header *hdr;
256 int ret;
257
258 /* Send COMPLETE_UPDATE_MODE command */
259
260 ret = s3fwrn5_fw_prep_msg(fw_info, &msg, S3FWRN5_FW_MSG_CMD,
261 S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE, NULL, 0);
262 if (ret < 0)
263 return ret;
264
265 ret = s3fwrn5_fw_send_msg(fw_info, msg, &rsp);
266 kfree_skb(msg);
267 if (ret < 0)
268 return ret;
269
270 hdr = (struct s3fwrn5_fw_header *) rsp->data;
271 if (hdr->code != S3FWRN5_FW_RET_SUCCESS)
272 ret = -EPROTO;
273
274 kfree_skb(rsp);
275
276 return ret;
277}
278
279/*
280 * Firmware header stucture:
281 *
282 * 0x00 - 0x0B : Date and time string (w/o NUL termination)
283 * 0x10 - 0x13 : Firmware version
284 * 0x14 - 0x17 : Signature address
285 * 0x18 - 0x1B : Signature size
286 * 0x1C - 0x1F : Firmware image address
287 * 0x20 - 0x23 : Firmware sectors count
288 * 0x24 - 0x27 : Custom signature address
289 * 0x28 - 0x2B : Custom signature size
290 */
291
292#define S3FWRN5_FW_IMAGE_HEADER_SIZE 44
293
294static int s3fwrn5_fw_request_firmware(struct s3fwrn5_fw_info *fw_info)
295{
296 struct s3fwrn5_fw_image *fw = &fw_info->fw;
297 u32 sig_off;
298 u32 image_off;
299 u32 custom_sig_off;
300 int ret;
301
302 ret = request_firmware(&fw->fw, fw_info->fw_name,
303 &fw_info->ndev->nfc_dev->dev);
304 if (ret < 0)
305 return ret;
306
307 if (fw->fw->size < S3FWRN5_FW_IMAGE_HEADER_SIZE)
308 return -EINVAL;
309
310 memcpy(fw->date, fw->fw->data + 0x00, 12);
311 fw->date[12] = '\0';
312
313 memcpy(&fw->version, fw->fw->data + 0x10, 4);
314
315 memcpy(&sig_off, fw->fw->data + 0x14, 4);
316 fw->sig = fw->fw->data + sig_off;
317 memcpy(&fw->sig_size, fw->fw->data + 0x18, 4);
318
319 memcpy(&image_off, fw->fw->data + 0x1C, 4);
320 fw->image = fw->fw->data + image_off;
321 memcpy(&fw->image_sectors, fw->fw->data + 0x20, 4);
322
323 memcpy(&custom_sig_off, fw->fw->data + 0x24, 4);
324 fw->custom_sig = fw->fw->data + custom_sig_off;
325 memcpy(&fw->custom_sig_size, fw->fw->data + 0x28, 4);
326
327 return 0;
328}
329
330static void s3fwrn5_fw_release_firmware(struct s3fwrn5_fw_info *fw_info)
331{
332 release_firmware(fw_info->fw.fw);
333}
334
335static int s3fwrn5_fw_get_base_addr(
336 struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo, u32 *base_addr)
337{
338 int i;
339 struct {
340 u8 version[4];
341 u32 base_addr;
342 } match[] = {
343 {{0x05, 0x00, 0x00, 0x00}, 0x00005000},
344 {{0x05, 0x00, 0x00, 0x01}, 0x00003000},
345 {{0x05, 0x00, 0x00, 0x02}, 0x00003000},
346 {{0x05, 0x00, 0x00, 0x03}, 0x00003000},
347 {{0x05, 0x00, 0x00, 0x05}, 0x00003000}
348 };
349
350 for (i = 0; i < ARRAY_SIZE(match); ++i)
351 if (bootinfo->hw_version[0] == match[i].version[0] &&
352 bootinfo->hw_version[1] == match[i].version[1] &&
353 bootinfo->hw_version[3] == match[i].version[3]) {
354 *base_addr = match[i].base_addr;
355 return 0;
356 }
357
358 return -EINVAL;
359}
360
361static inline bool
362s3fwrn5_fw_is_custom(struct s3fwrn5_fw_cmd_get_bootinfo_rsp *bootinfo)
363{
364 return !!bootinfo->hw_version[2];
365}
366
367int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info)
368{
369 struct s3fwrn5_fw_cmd_get_bootinfo_rsp bootinfo;
370 int ret;
371
372 /* Get firmware data */
373
374 ret = s3fwrn5_fw_request_firmware(fw_info);
375 if (ret < 0) {
376 dev_err(&fw_info->ndev->nfc_dev->dev,
377 "Failed to get fw file, ret=%02x\n", ret);
378 return ret;
379 }
380
381 /* Get bootloader info */
382
383 ret = s3fwrn5_fw_get_bootinfo(fw_info, &bootinfo);
384 if (ret < 0) {
385 dev_err(&fw_info->ndev->nfc_dev->dev,
386 "Failed to get bootinfo, ret=%02x\n", ret);
387 goto err;
388 }
389
390 /* Match hardware version to obtain firmware base address */
391
392 ret = s3fwrn5_fw_get_base_addr(&bootinfo, &fw_info->base_addr);
393 if (ret < 0) {
394 dev_err(&fw_info->ndev->nfc_dev->dev,
395 "Unknown hardware version\n");
396 goto err;
397 }
398
399 fw_info->sector_size = bootinfo.sector_size;
400
401 fw_info->sig_size = s3fwrn5_fw_is_custom(&bootinfo) ?
402 fw_info->fw.custom_sig_size : fw_info->fw.sig_size;
403 fw_info->sig = s3fwrn5_fw_is_custom(&bootinfo) ?
404 fw_info->fw.custom_sig : fw_info->fw.sig;
405
406 return 0;
407
408err:
409 s3fwrn5_fw_release_firmware(fw_info);
410 return ret;
411}
412
413bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version)
414{
415 struct s3fwrn5_fw_version *new = (void *) &fw_info->fw.version;
416 struct s3fwrn5_fw_version *old = (void *) &version;
417
418 if (new->major > old->major)
419 return true;
420 if (new->build1 > old->build1)
421 return true;
422 if (new->build2 > old->build2)
423 return true;
424
425 return false;
426}
427
428int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info)
429{
430 struct s3fwrn5_fw_image *fw = &fw_info->fw;
431 u8 hash_data[SHA1_DIGEST_SIZE];
432 struct scatterlist sg;
433 struct hash_desc desc;
434 u32 image_size, off;
435 int ret;
436
437 image_size = fw_info->sector_size * fw->image_sectors;
438
439 /* Compute SHA of firmware data */
440
441 sg_init_one(&sg, fw->image, image_size);
442 desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
443 crypto_hash_init(&desc);
444 crypto_hash_update(&desc, &sg, image_size);
445 crypto_hash_final(&desc, hash_data);
446 crypto_free_hash(desc.tfm);
447
448 /* Firmware update process */
449
450 dev_info(&fw_info->ndev->nfc_dev->dev,
451 "Firmware update: %s\n", fw_info->fw_name);
452
453 ret = s3fwrn5_fw_enter_update_mode(fw_info, hash_data,
454 SHA1_DIGEST_SIZE, fw_info->sig, fw_info->sig_size);
455 if (ret < 0) {
456 dev_err(&fw_info->ndev->nfc_dev->dev,
457 "Unable to enter update mode\n");
458 goto out;
459 }
460
461 for (off = 0; off < image_size; off += fw_info->sector_size) {
462 ret = s3fwrn5_fw_update_sector(fw_info,
463 fw_info->base_addr + off, fw->image + off);
464 if (ret < 0) {
465 dev_err(&fw_info->ndev->nfc_dev->dev,
466 "Firmware update error (code=%d)\n", ret);
467 goto out;
468 }
469 }
470
471 ret = s3fwrn5_fw_complete_update_mode(fw_info);
472 if (ret < 0) {
473 dev_err(&fw_info->ndev->nfc_dev->dev,
474 "Unable to complete update mode\n");
475 goto out;
476 }
477
478 dev_info(&fw_info->ndev->nfc_dev->dev,
479 "Firmware update: success\n");
480
481out:
482 return ret;
483}
484
485void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name)
486{
487 fw_info->parity = 0x00;
488 fw_info->rsp = NULL;
489 fw_info->fw.fw = NULL;
490 strcpy(fw_info->fw_name, fw_name);
491 init_completion(&fw_info->completion);
492}
493
494void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info)
495{
496 s3fwrn5_fw_release_firmware(fw_info);
497}
498
499int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
500{
501 struct s3fwrn5_info *info = nci_get_drvdata(ndev);
502 struct s3fwrn5_fw_info *fw_info = &info->fw_info;
503
504 BUG_ON(fw_info->rsp);
505
506 fw_info->rsp = skb;
507
508 complete(&fw_info->completion);
509
510 return 0;
511}
diff --git a/drivers/nfc/s3fwrn5/firmware.h b/drivers/nfc/s3fwrn5/firmware.h
new file mode 100644
index 000000000000..1ec0647ab917
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/firmware.h
@@ -0,0 +1,111 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef __LOCAL_S3FWRN5_FIRMWARE_H_
21#define __LOCAL_S3FWRN5_FIRMWARE_H_
22
23/* FW Message Types */
24#define S3FWRN5_FW_MSG_CMD 0x00
25#define S3FWRN5_FW_MSG_RSP 0x01
26#define S3FWRN5_FW_MSG_DATA 0x02
27
28/* FW Return Codes */
29#define S3FWRN5_FW_RET_SUCCESS 0x00
30#define S3FWRN5_FW_RET_MESSAGE_TYPE_INVALID 0x01
31#define S3FWRN5_FW_RET_COMMAND_INVALID 0x02
32#define S3FWRN5_FW_RET_PAGE_DATA_OVERFLOW 0x03
33#define S3FWRN5_FW_RET_SECT_DATA_OVERFLOW 0x04
34#define S3FWRN5_FW_RET_AUTHENTICATION_FAIL 0x05
35#define S3FWRN5_FW_RET_FLASH_OPERATION_FAIL 0x06
36#define S3FWRN5_FW_RET_ADDRESS_OUT_OF_RANGE 0x07
37#define S3FWRN5_FW_RET_PARAMETER_INVALID 0x08
38
39/* ---- FW Packet structures ---- */
40#define S3FWRN5_FW_HDR_SIZE 4
41
42struct s3fwrn5_fw_header {
43 __u8 type;
44 __u8 code;
45 __u16 len;
46};
47
48#define S3FWRN5_FW_CMD_RESET 0x00
49
50#define S3FWRN5_FW_CMD_GET_BOOTINFO 0x01
51
52struct s3fwrn5_fw_cmd_get_bootinfo_rsp {
53 __u8 hw_version[4];
54 __u16 sector_size;
55 __u16 page_size;
56 __u16 frame_max_size;
57 __u16 hw_buffer_size;
58};
59
60#define S3FWRN5_FW_CMD_ENTER_UPDATE_MODE 0x02
61
62struct s3fwrn5_fw_cmd_enter_updatemode {
63 __u16 hashcode_size;
64 __u16 signature_size;
65};
66
67#define S3FWRN5_FW_CMD_UPDATE_SECTOR 0x04
68
69struct s3fwrn5_fw_cmd_update_sector {
70 __u32 base_address;
71};
72
73#define S3FWRN5_FW_CMD_COMPLETE_UPDATE_MODE 0x05
74
75struct s3fwrn5_fw_image {
76 const struct firmware *fw;
77
78 char date[13];
79 u32 version;
80 const void *sig;
81 u32 sig_size;
82 const void *image;
83 u32 image_sectors;
84 const void *custom_sig;
85 u32 custom_sig_size;
86};
87
88struct s3fwrn5_fw_info {
89 struct nci_dev *ndev;
90 struct s3fwrn5_fw_image fw;
91 char fw_name[NFC_FIRMWARE_NAME_MAXSIZE + 1];
92
93 const void *sig;
94 u32 sig_size;
95 u32 sector_size;
96 u32 base_addr;
97
98 struct completion completion;
99 struct sk_buff *rsp;
100 char parity;
101};
102
103void s3fwrn5_fw_init(struct s3fwrn5_fw_info *fw_info, const char *fw_name);
104int s3fwrn5_fw_setup(struct s3fwrn5_fw_info *fw_info);
105bool s3fwrn5_fw_check_version(struct s3fwrn5_fw_info *fw_info, u32 version);
106int s3fwrn5_fw_download(struct s3fwrn5_fw_info *fw_info);
107void s3fwrn5_fw_cleanup(struct s3fwrn5_fw_info *fw_info);
108
109int s3fwrn5_fw_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
110
111#endif /* __LOCAL_S3FWRN5_FIRMWARE_H_ */
diff --git a/drivers/nfc/s3fwrn5/i2c.c b/drivers/nfc/s3fwrn5/i2c.c
new file mode 100644
index 000000000000..b4dd7dd47473
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/i2c.c
@@ -0,0 +1,306 @@
1/*
2 * I2C Link Layer for Samsung S3FWRN5 NCI based Driver
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/i2c.h>
21#include <linux/gpio.h>
22#include <linux/delay.h>
23#include <linux/of_gpio.h>
24#include <linux/of_irq.h>
25#include <linux/module.h>
26
27#include <net/nfc/nfc.h>
28
29#include "s3fwrn5.h"
30
31#define S3FWRN5_I2C_DRIVER_NAME "s3fwrn5_i2c"
32
33#define S3FWRN5_I2C_MAX_PAYLOAD 32
34#define S3FWRN5_EN_WAIT_TIME 150
35
36struct s3fwrn5_i2c_phy {
37 struct i2c_client *i2c_dev;
38 struct nci_dev *ndev;
39
40 unsigned int gpio_en;
41 unsigned int gpio_fw_wake;
42
43 struct mutex mutex;
44
45 enum s3fwrn5_mode mode;
46 unsigned int irq_skip:1;
47};
48
49static void s3fwrn5_i2c_set_wake(void *phy_id, bool wake)
50{
51 struct s3fwrn5_i2c_phy *phy = phy_id;
52
53 mutex_lock(&phy->mutex);
54 gpio_set_value(phy->gpio_fw_wake, wake);
55 msleep(S3FWRN5_EN_WAIT_TIME/2);
56 mutex_unlock(&phy->mutex);
57}
58
59static void s3fwrn5_i2c_set_mode(void *phy_id, enum s3fwrn5_mode mode)
60{
61 struct s3fwrn5_i2c_phy *phy = phy_id;
62
63 mutex_lock(&phy->mutex);
64
65 if (phy->mode == mode)
66 goto out;
67
68 phy->mode = mode;
69
70 gpio_set_value(phy->gpio_en, 1);
71 gpio_set_value(phy->gpio_fw_wake, 0);
72 if (mode == S3FWRN5_MODE_FW)
73 gpio_set_value(phy->gpio_fw_wake, 1);
74
75 if (mode != S3FWRN5_MODE_COLD) {
76 msleep(S3FWRN5_EN_WAIT_TIME);
77 gpio_set_value(phy->gpio_en, 0);
78 msleep(S3FWRN5_EN_WAIT_TIME/2);
79 }
80
81 phy->irq_skip = true;
82
83out:
84 mutex_unlock(&phy->mutex);
85}
86
87static enum s3fwrn5_mode s3fwrn5_i2c_get_mode(void *phy_id)
88{
89 struct s3fwrn5_i2c_phy *phy = phy_id;
90 enum s3fwrn5_mode mode;
91
92 mutex_lock(&phy->mutex);
93
94 mode = phy->mode;
95
96 mutex_unlock(&phy->mutex);
97
98 return mode;
99}
100
101static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
102{
103 struct s3fwrn5_i2c_phy *phy = phy_id;
104 int ret;
105
106 mutex_lock(&phy->mutex);
107
108 phy->irq_skip = false;
109
110 ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len);
111 if (ret == -EREMOTEIO) {
112 /* Retry, chip was in standby */
113 usleep_range(110000, 120000);
114 ret = i2c_master_send(phy->i2c_dev, skb->data, skb->len);
115 }
116
117 mutex_unlock(&phy->mutex);
118
119 if (ret < 0)
120 return ret;
121
122 if (ret != skb->len)
123 return -EREMOTEIO;
124
125 return 0;
126}
127
128static struct s3fwrn5_phy_ops i2c_phy_ops = {
129 .set_wake = s3fwrn5_i2c_set_wake,
130 .set_mode = s3fwrn5_i2c_set_mode,
131 .get_mode = s3fwrn5_i2c_get_mode,
132 .write = s3fwrn5_i2c_write,
133};
134
135static int s3fwrn5_i2c_read(struct s3fwrn5_i2c_phy *phy)
136{
137 struct sk_buff *skb;
138 size_t hdr_size;
139 size_t data_len;
140 char hdr[4];
141 int ret;
142
143 hdr_size = (phy->mode == S3FWRN5_MODE_NCI) ?
144 NCI_CTRL_HDR_SIZE : S3FWRN5_FW_HDR_SIZE;
145 ret = i2c_master_recv(phy->i2c_dev, hdr, hdr_size);
146 if (ret < 0)
147 return ret;
148
149 if (ret < hdr_size)
150 return -EBADMSG;
151
152 data_len = (phy->mode == S3FWRN5_MODE_NCI) ?
153 ((struct nci_ctrl_hdr *)hdr)->plen :
154 ((struct s3fwrn5_fw_header *)hdr)->len;
155
156 skb = alloc_skb(hdr_size + data_len, GFP_KERNEL);
157 if (!skb)
158 return -ENOMEM;
159
160 memcpy(skb_put(skb, hdr_size), hdr, hdr_size);
161
162 if (data_len == 0)
163 goto out;
164
165 ret = i2c_master_recv(phy->i2c_dev, skb_put(skb, data_len), data_len);
166 if (ret != data_len) {
167 kfree_skb(skb);
168 return -EBADMSG;
169 }
170
171out:
172 return s3fwrn5_recv_frame(phy->ndev, skb, phy->mode);
173}
174
175static irqreturn_t s3fwrn5_i2c_irq_thread_fn(int irq, void *phy_id)
176{
177 struct s3fwrn5_i2c_phy *phy = phy_id;
178 int ret = 0;
179
180 if (!phy || !phy->ndev) {
181 WARN_ON_ONCE(1);
182 return IRQ_NONE;
183 }
184
185 mutex_lock(&phy->mutex);
186
187 if (phy->irq_skip)
188 goto out;
189
190 switch (phy->mode) {
191 case S3FWRN5_MODE_NCI:
192 case S3FWRN5_MODE_FW:
193 ret = s3fwrn5_i2c_read(phy);
194 break;
195 case S3FWRN5_MODE_COLD:
196 ret = -EREMOTEIO;
197 break;
198 }
199
200out:
201 mutex_unlock(&phy->mutex);
202
203 return IRQ_HANDLED;
204}
205
206static int s3fwrn5_i2c_parse_dt(struct i2c_client *client)
207{
208 struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client);
209 struct device_node *np = client->dev.of_node;
210
211 if (!np)
212 return -ENODEV;
213
214 phy->gpio_en = of_get_named_gpio(np, "s3fwrn5,en-gpios", 0);
215 if (!gpio_is_valid(phy->gpio_en))
216 return -ENODEV;
217
218 phy->gpio_fw_wake = of_get_named_gpio(np, "s3fwrn5,fw-gpios", 0);
219 if (!gpio_is_valid(phy->gpio_fw_wake))
220 return -ENODEV;
221
222 return 0;
223}
224
225static int s3fwrn5_i2c_probe(struct i2c_client *client,
226 const struct i2c_device_id *id)
227{
228 struct s3fwrn5_i2c_phy *phy;
229 int ret;
230
231 phy = devm_kzalloc(&client->dev, sizeof(*phy), GFP_KERNEL);
232 if (!phy)
233 return -ENOMEM;
234
235 mutex_init(&phy->mutex);
236 phy->mode = S3FWRN5_MODE_COLD;
237 phy->irq_skip = true;
238
239 phy->i2c_dev = client;
240 i2c_set_clientdata(client, phy);
241
242 ret = s3fwrn5_i2c_parse_dt(client);
243 if (ret < 0)
244 return ret;
245
246 ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_en,
247 GPIOF_OUT_INIT_HIGH, "s3fwrn5_en");
248 if (ret < 0)
249 return ret;
250
251 ret = devm_gpio_request_one(&phy->i2c_dev->dev, phy->gpio_fw_wake,
252 GPIOF_OUT_INIT_LOW, "s3fwrn5_fw_wake");
253 if (ret < 0)
254 return ret;
255
256 ret = s3fwrn5_probe(&phy->ndev, phy, &phy->i2c_dev->dev, &i2c_phy_ops,
257 S3FWRN5_I2C_MAX_PAYLOAD);
258 if (ret < 0)
259 return ret;
260
261 ret = request_threaded_irq(phy->i2c_dev->irq, NULL,
262 s3fwrn5_i2c_irq_thread_fn, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
263 S3FWRN5_I2C_DRIVER_NAME, phy);
264 if (ret)
265 s3fwrn5_remove(phy->ndev);
266
267 return ret;
268}
269
270static int s3fwrn5_i2c_remove(struct i2c_client *client)
271{
272 struct s3fwrn5_i2c_phy *phy = i2c_get_clientdata(client);
273
274 s3fwrn5_remove(phy->ndev);
275
276 return 0;
277}
278
279static struct i2c_device_id s3fwrn5_i2c_id_table[] = {
280 {S3FWRN5_I2C_DRIVER_NAME, 0},
281 {}
282};
283MODULE_DEVICE_TABLE(i2c, s3fwrn5_i2c_id_table);
284
285static const struct of_device_id of_s3fwrn5_i2c_match[] = {
286 { .compatible = "samsung,s3fwrn5-i2c", },
287 {}
288};
289MODULE_DEVICE_TABLE(of, of_s3fwrn5_i2c_match);
290
291static struct i2c_driver s3fwrn5_i2c_driver = {
292 .driver = {
293 .owner = THIS_MODULE,
294 .name = S3FWRN5_I2C_DRIVER_NAME,
295 .of_match_table = of_match_ptr(of_s3fwrn5_i2c_match),
296 },
297 .probe = s3fwrn5_i2c_probe,
298 .remove = s3fwrn5_i2c_remove,
299 .id_table = s3fwrn5_i2c_id_table,
300};
301
302module_i2c_driver(s3fwrn5_i2c_driver);
303
304MODULE_LICENSE("GPL");
305MODULE_DESCRIPTION("I2C driver for Samsung S3FWRN5");
306MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");
diff --git a/drivers/nfc/s3fwrn5/nci.c b/drivers/nfc/s3fwrn5/nci.c
new file mode 100644
index 000000000000..ace0071c5339
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/nci.c
@@ -0,0 +1,165 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/completion.h>
21#include <linux/firmware.h>
22
23#include "s3fwrn5.h"
24#include "nci.h"
25
26static int s3fwrn5_nci_prop_rsp(struct nci_dev *ndev, struct sk_buff *skb)
27{
28 __u8 status = skb->data[0];
29
30 nci_req_complete(ndev, status);
31 return 0;
32}
33
34static struct nci_prop_ops s3fwrn5_nci_prop_ops[] = {
35 {
36 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
37 NCI_PROP_AGAIN),
38 .rsp = s3fwrn5_nci_prop_rsp,
39 },
40 {
41 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
42 NCI_PROP_GET_RFREG),
43 .rsp = s3fwrn5_nci_prop_rsp,
44 },
45 {
46 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
47 NCI_PROP_SET_RFREG),
48 .rsp = s3fwrn5_nci_prop_rsp,
49 },
50 {
51 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
52 NCI_PROP_GET_RFREG_VER),
53 .rsp = s3fwrn5_nci_prop_rsp,
54 },
55 {
56 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
57 NCI_PROP_SET_RFREG_VER),
58 .rsp = s3fwrn5_nci_prop_rsp,
59 },
60 {
61 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
62 NCI_PROP_START_RFREG),
63 .rsp = s3fwrn5_nci_prop_rsp,
64 },
65 {
66 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
67 NCI_PROP_STOP_RFREG),
68 .rsp = s3fwrn5_nci_prop_rsp,
69 },
70 {
71 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
72 NCI_PROP_FW_CFG),
73 .rsp = s3fwrn5_nci_prop_rsp,
74 },
75 {
76 .opcode = nci_opcode_pack(NCI_GID_PROPRIETARY,
77 NCI_PROP_WR_RESET),
78 .rsp = s3fwrn5_nci_prop_rsp,
79 },
80};
81
82void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n)
83{
84 *ops = s3fwrn5_nci_prop_ops;
85 *n = ARRAY_SIZE(s3fwrn5_nci_prop_ops);
86}
87
88#define S3FWRN5_RFREG_SECTION_SIZE 252
89
90int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name)
91{
92 const struct firmware *fw;
93 struct nci_prop_fw_cfg_cmd fw_cfg;
94 struct nci_prop_set_rfreg_cmd set_rfreg;
95 struct nci_prop_stop_rfreg_cmd stop_rfreg;
96 u32 checksum;
97 int i, len;
98 int ret;
99
100 ret = request_firmware(&fw, fw_name, &info->ndev->nfc_dev->dev);
101 if (ret < 0)
102 return ret;
103
104 /* Compute rfreg checksum */
105
106 checksum = 0;
107 for (i = 0; i < fw->size; i += 4)
108 checksum += *((u32 *)(fw->data+i));
109
110 /* Set default clock configuration for external crystal */
111
112 fw_cfg.clk_type = 0x01;
113 fw_cfg.clk_speed = 0xff;
114 fw_cfg.clk_req = 0xff;
115 ret = nci_prop_cmd(info->ndev, NCI_PROP_FW_CFG,
116 sizeof(fw_cfg), (__u8 *)&fw_cfg);
117 if (ret < 0)
118 goto out;
119
120 /* Start rfreg configuration */
121
122 dev_info(&info->ndev->nfc_dev->dev,
123 "rfreg configuration update: %s\n", fw_name);
124
125 ret = nci_prop_cmd(info->ndev, NCI_PROP_START_RFREG, 0, NULL);
126 if (ret < 0) {
127 dev_err(&info->ndev->nfc_dev->dev,
128 "Unable to start rfreg update\n");
129 goto out;
130 }
131
132 /* Update rfreg */
133
134 set_rfreg.index = 0;
135 for (i = 0; i < fw->size; i += S3FWRN5_RFREG_SECTION_SIZE) {
136 len = (fw->size - i < S3FWRN5_RFREG_SECTION_SIZE) ?
137 (fw->size - i) : S3FWRN5_RFREG_SECTION_SIZE;
138 memcpy(set_rfreg.data, fw->data+i, len);
139 ret = nci_prop_cmd(info->ndev, NCI_PROP_SET_RFREG,
140 len+1, (__u8 *)&set_rfreg);
141 if (ret < 0) {
142 dev_err(&info->ndev->nfc_dev->dev,
143 "rfreg update error (code=%d)\n", ret);
144 goto out;
145 }
146 set_rfreg.index++;
147 }
148
149 /* Finish rfreg configuration */
150
151 stop_rfreg.checksum = checksum & 0xffff;
152 ret = nci_prop_cmd(info->ndev, NCI_PROP_STOP_RFREG,
153 sizeof(stop_rfreg), (__u8 *)&stop_rfreg);
154 if (ret < 0) {
155 dev_err(&info->ndev->nfc_dev->dev,
156 "Unable to stop rfreg update\n");
157 goto out;
158 }
159
160 dev_info(&info->ndev->nfc_dev->dev,
161 "rfreg configuration update: success\n");
162out:
163 release_firmware(fw);
164 return ret;
165}
diff --git a/drivers/nfc/s3fwrn5/nci.h b/drivers/nfc/s3fwrn5/nci.h
new file mode 100644
index 000000000000..0e68d439dde6
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/nci.h
@@ -0,0 +1,89 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef __LOCAL_S3FWRN5_NCI_H_
21#define __LOCAL_S3FWRN5_NCI_H_
22
23#include "s3fwrn5.h"
24
25#define NCI_PROP_AGAIN 0x01
26
27#define NCI_PROP_GET_RFREG 0x21
28#define NCI_PROP_SET_RFREG 0x22
29
30struct nci_prop_set_rfreg_cmd {
31 __u8 index;
32 __u8 data[252];
33};
34
35struct nci_prop_set_rfreg_rsp {
36 __u8 status;
37};
38
39#define NCI_PROP_GET_RFREG_VER 0x24
40
41struct nci_prop_get_rfreg_ver_rsp {
42 __u8 status;
43 __u8 data[8];
44};
45
46#define NCI_PROP_SET_RFREG_VER 0x25
47
48struct nci_prop_set_rfreg_ver_cmd {
49 __u8 data[8];
50};
51
52struct nci_prop_set_rfreg_ver_rsp {
53 __u8 status;
54};
55
56#define NCI_PROP_START_RFREG 0x26
57
58struct nci_prop_start_rfreg_rsp {
59 __u8 status;
60};
61
62#define NCI_PROP_STOP_RFREG 0x27
63
64struct nci_prop_stop_rfreg_cmd {
65 __u16 checksum;
66};
67
68struct nci_prop_stop_rfreg_rsp {
69 __u8 status;
70};
71
72#define NCI_PROP_FW_CFG 0x28
73
74struct nci_prop_fw_cfg_cmd {
75 __u8 clk_type;
76 __u8 clk_speed;
77 __u8 clk_req;
78};
79
80struct nci_prop_fw_cfg_rsp {
81 __u8 status;
82};
83
84#define NCI_PROP_WR_RESET 0x2f
85
86void s3fwrn5_nci_get_prop_ops(struct nci_prop_ops **ops, size_t *n);
87int s3fwrn5_nci_rf_configure(struct s3fwrn5_info *info, const char *fw_name);
88
89#endif /* __LOCAL_S3FWRN5_NCI_H_ */
diff --git a/drivers/nfc/s3fwrn5/s3fwrn5.h b/drivers/nfc/s3fwrn5/s3fwrn5.h
new file mode 100644
index 000000000000..89210d4828b8
--- /dev/null
+++ b/drivers/nfc/s3fwrn5/s3fwrn5.h
@@ -0,0 +1,99 @@
1/*
2 * NCI based driver for Samsung S3FWRN5 NFC chip
3 *
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2 or later, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef __LOCAL_S3FWRN5_H_
21#define __LOCAL_S3FWRN5_H_
22
23#include <linux/nfc.h>
24
25#include <net/nfc/nci_core.h>
26
27#include "firmware.h"
28
29enum s3fwrn5_mode {
30 S3FWRN5_MODE_COLD,
31 S3FWRN5_MODE_NCI,
32 S3FWRN5_MODE_FW,
33};
34
35struct s3fwrn5_phy_ops {
36 void (*set_wake)(void *id, bool sleep);
37 void (*set_mode)(void *id, enum s3fwrn5_mode);
38 enum s3fwrn5_mode (*get_mode)(void *id);
39 int (*write)(void *id, struct sk_buff *skb);
40};
41
42struct s3fwrn5_info {
43 struct nci_dev *ndev;
44 void *phy_id;
45 struct device *pdev;
46
47 struct s3fwrn5_phy_ops *phy_ops;
48 unsigned int max_payload;
49
50 struct s3fwrn5_fw_info fw_info;
51
52 struct mutex mutex;
53};
54
55static inline int s3fwrn5_set_mode(struct s3fwrn5_info *info,
56 enum s3fwrn5_mode mode)
57{
58 if (!info->phy_ops->set_mode)
59 return -ENOTSUPP;
60
61 info->phy_ops->set_mode(info->phy_id, mode);
62
63 return 0;
64}
65
66static inline enum s3fwrn5_mode s3fwrn5_get_mode(struct s3fwrn5_info *info)
67{
68 if (!info->phy_ops->get_mode)
69 return -ENOTSUPP;
70
71 return info->phy_ops->get_mode(info->phy_id);
72}
73
74static inline int s3fwrn5_set_wake(struct s3fwrn5_info *info, bool wake)
75{
76 if (!info->phy_ops->set_wake)
77 return -ENOTSUPP;
78
79 info->phy_ops->set_wake(info->phy_id, wake);
80
81 return 0;
82}
83
84static inline int s3fwrn5_write(struct s3fwrn5_info *info, struct sk_buff *skb)
85{
86 if (!info->phy_ops->write)
87 return -ENOTSUPP;
88
89 return info->phy_ops->write(info->phy_id, skb);
90}
91
92int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
93 struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload);
94void s3fwrn5_remove(struct nci_dev *ndev);
95
96int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,
97 enum s3fwrn5_mode mode);
98
99#endif /* __LOCAL_S3FWRN5_H_ */
diff --git a/drivers/nfc/st-nci/Kconfig b/drivers/nfc/st-nci/Kconfig
index fc3904c946ee..e7c6db9c5860 100644
--- a/drivers/nfc/st-nci/Kconfig
+++ b/drivers/nfc/st-nci/Kconfig
@@ -21,3 +21,14 @@ config NFC_ST_NCI_I2C
21 21
22 If you choose to build a module, it'll be called st-nci_i2c. 22 If you choose to build a module, it'll be called st-nci_i2c.
23 Say N if unsure. 23 Say N if unsure.
24
25config NFC_ST_NCI_SPI
26 tristate "NFC ST NCI spi support"
27 depends on NFC_ST_NCI && SPI
28 ---help---
29 This module adds support for an SPI interface to the
30 STMicroelectronics NFC NCI chips familly.
31 Select this if your platform is using the spi bus.
32
33 If you choose to build a module, it'll be called st-nci_spi.
34 Say N if unsure.
diff --git a/drivers/nfc/st-nci/Makefile b/drivers/nfc/st-nci/Makefile
index 0df157df3a94..348ce76f2177 100644
--- a/drivers/nfc/st-nci/Makefile
+++ b/drivers/nfc/st-nci/Makefile
@@ -7,3 +7,6 @@ obj-$(CONFIG_NFC_ST_NCI) += st-nci.o
7 7
8st-nci_i2c-objs = i2c.o 8st-nci_i2c-objs = i2c.o
9obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o 9obj-$(CONFIG_NFC_ST_NCI_I2C) += st-nci_i2c.o
10
11st-nci_spi-objs = spi.o
12obj-$(CONFIG_NFC_ST_NCI_SPI) += st-nci_spi.o
diff --git a/drivers/nfc/st-nci/i2c.c b/drivers/nfc/st-nci/i2c.c
index 06175ce769bb..707ed2eb5936 100644
--- a/drivers/nfc/st-nci/i2c.c
+++ b/drivers/nfc/st-nci/i2c.c
@@ -25,15 +25,15 @@
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/nfc.h> 27#include <linux/nfc.h>
28#include <linux/platform_data/st_nci.h> 28#include <linux/platform_data/st-nci.h>
29 29
30#include "ndlc.h" 30#include "ndlc.h"
31 31
32#define DRIVER_DESC "NCI NFC driver for ST21NFCB" 32#define DRIVER_DESC "NCI NFC driver for ST_NCI"
33 33
34/* ndlc header */ 34/* ndlc header */
35#define ST21NFCB_FRAME_HEADROOM 1 35#define ST_NCI_FRAME_HEADROOM 1
36#define ST21NFCB_FRAME_TAILROOM 0 36#define ST_NCI_FRAME_TAILROOM 0
37 37
38#define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */ 38#define ST_NCI_I2C_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
39#define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */ 39#define ST_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
@@ -118,15 +118,10 @@ static int st_nci_i2c_write(void *phy_id, struct sk_buff *skb)
118/* 118/*
119 * Reads an ndlc frame and returns it in a newly allocated sk_buff. 119 * Reads an ndlc frame and returns it in a newly allocated sk_buff.
120 * returns: 120 * returns:
121 * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at 121 * 0 : if received frame is complete
122 * end of read)
123 * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF
124 * at end of read)
125 * -EREMOTEIO : i2c read error (fatal) 122 * -EREMOTEIO : i2c read error (fatal)
126 * -EBADMSG : frame was incorrect and discarded 123 * -EBADMSG : frame was incorrect and discarded
127 * (value returned from st_nci_i2c_repack) 124 * -ENOMEM : cannot allocate skb, frame dropped
128 * -EIO : if no ST21NFCB_SOF_EOF is found after reaching
129 * the read length end sequence
130 */ 125 */
131static int st_nci_i2c_read(struct st_nci_i2c_phy *phy, 126static int st_nci_i2c_read(struct st_nci_i2c_phy *phy,
132 struct sk_buff **skb) 127 struct sk_buff **skb)
@@ -179,7 +174,7 @@ static int st_nci_i2c_read(struct st_nci_i2c_phy *phy,
179/* 174/*
180 * Reads an ndlc frame from the chip. 175 * Reads an ndlc frame from the chip.
181 * 176 *
182 * On ST21NFCB, IRQ goes in idle state when read starts. 177 * On ST_NCI, IRQ goes in idle state when read starts.
183 */ 178 */
184static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id) 179static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
185{ 180{
@@ -325,12 +320,12 @@ static int st_nci_i2c_probe(struct i2c_client *client,
325 } 320 }
326 } else { 321 } else {
327 nfc_err(&client->dev, 322 nfc_err(&client->dev,
328 "st21nfcb platform resources not available\n"); 323 "st_nci platform resources not available\n");
329 return -ENODEV; 324 return -ENODEV;
330 } 325 }
331 326
332 r = ndlc_probe(phy, &i2c_phy_ops, &client->dev, 327 r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
333 ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM, 328 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
334 &phy->ndlc); 329 &phy->ndlc);
335 if (r < 0) { 330 if (r < 0) {
336 nfc_err(&client->dev, "Unable to register ndlc layer\n"); 331 nfc_err(&client->dev, "Unable to register ndlc layer\n");
diff --git a/drivers/nfc/st-nci/ndlc.c b/drivers/nfc/st-nci/ndlc.c
index 56c6a4cb4c96..d2cf84e680c6 100644
--- a/drivers/nfc/st-nci/ndlc.c
+++ b/drivers/nfc/st-nci/ndlc.c
@@ -171,6 +171,8 @@ static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc)
171 if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) { 171 if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) {
172 switch (pcb & PCB_SYNC_MASK) { 172 switch (pcb & PCB_SYNC_MASK) {
173 case PCB_SYNC_ACK: 173 case PCB_SYNC_ACK:
174 skb = skb_dequeue(&ndlc->ack_pending_q);
175 kfree_skb(skb);
174 del_timer_sync(&ndlc->t1_timer); 176 del_timer_sync(&ndlc->t1_timer);
175 del_timer_sync(&ndlc->t2_timer); 177 del_timer_sync(&ndlc->t2_timer);
176 ndlc->t2_active = false; 178 ndlc->t2_active = false;
@@ -192,12 +194,13 @@ static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc)
192 msecs_to_jiffies(NDLC_TIMER_T1_WAIT)); 194 msecs_to_jiffies(NDLC_TIMER_T1_WAIT));
193 break; 195 break;
194 default: 196 default:
195 pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
196 kfree_skb(skb); 197 kfree_skb(skb);
197 break; 198 break;
198 } 199 }
199 } else { 200 } else if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_DATAFRAME) {
200 nci_recv_frame(ndlc->ndev, skb); 201 nci_recv_frame(ndlc->ndev, skb);
202 } else {
203 kfree_skb(skb);
201 } 204 }
202 } 205 }
203} 206}
diff --git a/drivers/nfc/st-nci/spi.c b/drivers/nfc/st-nci/spi.c
new file mode 100644
index 000000000000..598a58c4d6d1
--- /dev/null
+++ b/drivers/nfc/st-nci/spi.c
@@ -0,0 +1,392 @@
1/*
2 * SPI Link Layer for ST NCI based Driver
3 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/module.h>
21#include <linux/spi/spi.h>
22#include <linux/gpio.h>
23#include <linux/of_irq.h>
24#include <linux/of_gpio.h>
25#include <linux/interrupt.h>
26#include <linux/delay.h>
27#include <linux/nfc.h>
28#include <linux/platform_data/st-nci.h>
29
30#include "ndlc.h"
31
32#define DRIVER_DESC "NCI NFC driver for ST_NCI"
33
34/* ndlc header */
35#define ST_NCI_FRAME_HEADROOM 1
36#define ST_NCI_FRAME_TAILROOM 0
37
38#define ST_NCI_SPI_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
39#define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */
40
41#define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
42
43static struct spi_device_id st_nci_spi_id_table[] = {
44 {ST_NCI_SPI_DRIVER_NAME, 0},
45 {}
46};
47MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
48
49struct st_nci_spi_phy {
50 struct spi_device *spi_dev;
51 struct llt_ndlc *ndlc;
52
53 unsigned int gpio_reset;
54 unsigned int irq_polarity;
55};
56
57#define SPI_DUMP_SKB(info, skb) \
58do { \
59 pr_debug("%s:\n", info); \
60 print_hex_dump(KERN_DEBUG, "spi: ", DUMP_PREFIX_OFFSET, \
61 16, 1, (skb)->data, (skb)->len, 0); \
62} while (0)
63
64static int st_nci_spi_enable(void *phy_id)
65{
66 struct st_nci_spi_phy *phy = phy_id;
67
68 gpio_set_value(phy->gpio_reset, 0);
69 usleep_range(10000, 15000);
70 gpio_set_value(phy->gpio_reset, 1);
71 usleep_range(80000, 85000);
72
73 if (phy->ndlc->powered == 0)
74 enable_irq(phy->spi_dev->irq);
75
76 return 0;
77}
78
79static void st_nci_spi_disable(void *phy_id)
80{
81 struct st_nci_spi_phy *phy = phy_id;
82
83 disable_irq_nosync(phy->spi_dev->irq);
84}
85
86/*
87 * Writing a frame must not return the number of written bytes.
88 * It must return either zero for success, or <0 for error.
89 * In addition, it must not alter the skb
90 */
91static int st_nci_spi_write(void *phy_id, struct sk_buff *skb)
92{
93 int r;
94 struct st_nci_spi_phy *phy = phy_id;
95 struct spi_device *dev = phy->spi_dev;
96 struct sk_buff *skb_rx;
97 u8 buf[ST_NCI_SPI_MAX_SIZE];
98 struct spi_transfer spi_xfer = {
99 .tx_buf = skb->data,
100 .rx_buf = buf,
101 .len = skb->len,
102 };
103
104 SPI_DUMP_SKB("st_nci_spi_write", skb);
105
106 if (phy->ndlc->hard_fault != 0)
107 return phy->ndlc->hard_fault;
108
109 r = spi_sync_transfer(dev, &spi_xfer, 1);
110 /*
111 * We may have received some valuable data on miso line.
112 * Send them back in the ndlc state machine.
113 */
114 if (!r) {
115 skb_rx = alloc_skb(skb->len, GFP_KERNEL);
116 if (!skb_rx) {
117 r = -ENOMEM;
118 goto exit;
119 }
120
121 skb_put(skb_rx, skb->len);
122 memcpy(skb_rx->data, buf, skb->len);
123 ndlc_recv(phy->ndlc, skb_rx);
124 }
125
126exit:
127 return r;
128}
129
130/*
131 * Reads an ndlc frame and returns it in a newly allocated sk_buff.
132 * returns:
133 * 0 : if received frame is complete
134 * -EREMOTEIO : i2c read error (fatal)
135 * -EBADMSG : frame was incorrect and discarded
136 * -ENOMEM : cannot allocate skb, frame dropped
137 */
138static int st_nci_spi_read(struct st_nci_spi_phy *phy,
139 struct sk_buff **skb)
140{
141 int r;
142 u8 len;
143 u8 buf[ST_NCI_SPI_MAX_SIZE];
144 struct spi_device *dev = phy->spi_dev;
145 struct spi_transfer spi_xfer = {
146 .rx_buf = buf,
147 .len = ST_NCI_SPI_MIN_SIZE,
148 };
149
150 r = spi_sync_transfer(dev, &spi_xfer, 1);
151 if (r < 0)
152 return -EREMOTEIO;
153
154 len = be16_to_cpu(*(__be16 *) (buf + 2));
155 if (len > ST_NCI_SPI_MAX_SIZE) {
156 nfc_err(&dev->dev, "invalid frame len\n");
157 phy->ndlc->hard_fault = 1;
158 return -EBADMSG;
159 }
160
161 *skb = alloc_skb(ST_NCI_SPI_MIN_SIZE + len, GFP_KERNEL);
162 if (*skb == NULL)
163 return -ENOMEM;
164
165 skb_reserve(*skb, ST_NCI_SPI_MIN_SIZE);
166 skb_put(*skb, ST_NCI_SPI_MIN_SIZE);
167 memcpy((*skb)->data, buf, ST_NCI_SPI_MIN_SIZE);
168
169 if (!len)
170 return 0;
171
172 spi_xfer.len = len;
173 r = spi_sync_transfer(dev, &spi_xfer, 1);
174 if (r < 0) {
175 kfree_skb(*skb);
176 return -EREMOTEIO;
177 }
178
179 skb_put(*skb, len);
180 memcpy((*skb)->data + ST_NCI_SPI_MIN_SIZE, buf, len);
181
182 SPI_DUMP_SKB("spi frame read", *skb);
183
184 return 0;
185}
186
187/*
188 * Reads an ndlc frame from the chip.
189 *
190 * On ST21NFCB, IRQ goes in idle state when read starts.
191 */
192static irqreturn_t st_nci_irq_thread_fn(int irq, void *phy_id)
193{
194 struct st_nci_spi_phy *phy = phy_id;
195 struct spi_device *dev;
196 struct sk_buff *skb = NULL;
197 int r;
198
199 if (!phy || !phy->ndlc || irq != phy->spi_dev->irq) {
200 WARN_ON_ONCE(1);
201 return IRQ_NONE;
202 }
203
204 dev = phy->spi_dev;
205 dev_dbg(&dev->dev, "IRQ\n");
206
207 if (phy->ndlc->hard_fault)
208 return IRQ_HANDLED;
209
210 if (!phy->ndlc->powered) {
211 st_nci_spi_disable(phy);
212 return IRQ_HANDLED;
213 }
214
215 r = st_nci_spi_read(phy, &skb);
216 if (r == -EREMOTEIO || r == -ENOMEM || r == -EBADMSG)
217 return IRQ_HANDLED;
218
219 ndlc_recv(phy->ndlc, skb);
220
221 return IRQ_HANDLED;
222}
223
224static struct nfc_phy_ops spi_phy_ops = {
225 .write = st_nci_spi_write,
226 .enable = st_nci_spi_enable,
227 .disable = st_nci_spi_disable,
228};
229
230#ifdef CONFIG_OF
231static int st_nci_spi_of_request_resources(struct spi_device *dev)
232{
233 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
234 struct device_node *pp;
235 int gpio;
236 int r;
237
238 pp = dev->dev.of_node;
239 if (!pp)
240 return -ENODEV;
241
242 /* Get GPIO from device tree */
243 gpio = of_get_named_gpio(pp, "reset-gpios", 0);
244 if (gpio < 0) {
245 nfc_err(&dev->dev,
246 "Failed to retrieve reset-gpios from device tree\n");
247 return gpio;
248 }
249
250 /* GPIO request and configuration */
251 r = devm_gpio_request_one(&dev->dev, gpio,
252 GPIOF_OUT_INIT_HIGH, "clf_reset");
253 if (r) {
254 nfc_err(&dev->dev, "Failed to request reset pin\n");
255 return r;
256 }
257 phy->gpio_reset = gpio;
258
259 phy->irq_polarity = irq_get_trigger_type(dev->irq);
260
261 return 0;
262}
263#else
264static int st_nci_spi_of_request_resources(struct spi_device *dev)
265{
266 return -ENODEV;
267}
268#endif
269
270static int st_nci_spi_request_resources(struct spi_device *dev)
271{
272 struct st_nci_nfc_platform_data *pdata;
273 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
274 int r;
275
276 pdata = dev->dev.platform_data;
277 if (pdata == NULL) {
278 nfc_err(&dev->dev, "No platform data\n");
279 return -EINVAL;
280 }
281
282 /* store for later use */
283 phy->gpio_reset = pdata->gpio_reset;
284 phy->irq_polarity = pdata->irq_polarity;
285
286 r = devm_gpio_request_one(&dev->dev,
287 phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
288 if (r) {
289 pr_err("%s : reset gpio_request failed\n", __FILE__);
290 return r;
291 }
292
293 return 0;
294}
295
296static int st_nci_spi_probe(struct spi_device *dev)
297{
298 struct st_nci_spi_phy *phy;
299 struct st_nci_nfc_platform_data *pdata;
300 int r;
301
302 dev_dbg(&dev->dev, "%s\n", __func__);
303 dev_dbg(&dev->dev, "IRQ: %d\n", dev->irq);
304
305 /* Check SPI platform functionnalities */
306 if (!dev) {
307 pr_debug("%s: dev is NULL. Device is not accessible.\n",
308 __func__);
309 return -ENODEV;
310 }
311
312 phy = devm_kzalloc(&dev->dev, sizeof(struct st_nci_spi_phy),
313 GFP_KERNEL);
314 if (!phy)
315 return -ENOMEM;
316
317 phy->spi_dev = dev;
318
319 spi_set_drvdata(dev, phy);
320
321 pdata = dev->dev.platform_data;
322 if (!pdata && dev->dev.of_node) {
323 r = st_nci_spi_of_request_resources(dev);
324 if (r) {
325 nfc_err(&dev->dev, "No platform data\n");
326 return r;
327 }
328 } else if (pdata) {
329 r = st_nci_spi_request_resources(dev);
330 if (r) {
331 nfc_err(&dev->dev,
332 "Cannot get platform resources\n");
333 return r;
334 }
335 } else {
336 nfc_err(&dev->dev,
337 "st_nci platform resources not available\n");
338 return -ENODEV;
339 }
340
341 r = ndlc_probe(phy, &spi_phy_ops, &dev->dev,
342 ST_NCI_FRAME_HEADROOM, ST_NCI_FRAME_TAILROOM,
343 &phy->ndlc);
344 if (r < 0) {
345 nfc_err(&dev->dev, "Unable to register ndlc layer\n");
346 return r;
347 }
348
349 r = devm_request_threaded_irq(&dev->dev, dev->irq, NULL,
350 st_nci_irq_thread_fn,
351 phy->irq_polarity | IRQF_ONESHOT,
352 ST_NCI_SPI_DRIVER_NAME, phy);
353 if (r < 0)
354 nfc_err(&dev->dev, "Unable to register IRQ handler\n");
355
356 return r;
357}
358
359static int st_nci_spi_remove(struct spi_device *dev)
360{
361 struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
362
363 dev_dbg(&dev->dev, "%s\n", __func__);
364
365 ndlc_remove(phy->ndlc);
366
367 return 0;
368}
369
370#ifdef CONFIG_OF
371static const struct of_device_id of_st_nci_spi_match[] = {
372 { .compatible = "st,st21nfcb-spi", },
373 {}
374};
375MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
376#endif
377
378static struct spi_driver st_nci_spi_driver = {
379 .driver = {
380 .owner = THIS_MODULE,
381 .name = ST_NCI_SPI_DRIVER_NAME,
382 .of_match_table = of_match_ptr(of_st_nci_spi_match),
383 },
384 .probe = st_nci_spi_probe,
385 .id_table = st_nci_spi_id_table,
386 .remove = st_nci_spi_remove,
387};
388
389module_spi_driver(st_nci_spi_driver);
390
391MODULE_LICENSE("GPL");
392MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st-nci/st-nci_se.c b/drivers/nfc/st-nci/st-nci_se.c
index 97addfa96c6f..c742ef65a05a 100644
--- a/drivers/nfc/st-nci/st-nci_se.c
+++ b/drivers/nfc/st-nci/st-nci_se.c
@@ -189,14 +189,14 @@ int st_nci_hci_load_session(struct nci_dev *ndev)
189 ST_NCI_DEVICE_MGNT_GATE, 189 ST_NCI_DEVICE_MGNT_GATE,
190 ST_NCI_DEVICE_MGNT_PIPE); 190 ST_NCI_DEVICE_MGNT_PIPE);
191 if (r < 0) 191 if (r < 0)
192 goto free_info; 192 return r;
193 193
194 /* Get pipe list */ 194 /* Get pipe list */
195 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, 195 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
196 ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list), 196 ST_NCI_DM_GETINFO, pipe_list, sizeof(pipe_list),
197 &skb_pipe_list); 197 &skb_pipe_list);
198 if (r < 0) 198 if (r < 0)
199 goto free_info; 199 return r;
200 200
201 /* Complete the existing gate_pipe table */ 201 /* Complete the existing gate_pipe table */
202 for (i = 0; i < skb_pipe_list->len; i++) { 202 for (i = 0; i < skb_pipe_list->len; i++) {
@@ -222,6 +222,7 @@ int st_nci_hci_load_session(struct nci_dev *ndev)
222 dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) { 222 dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) {
223 pr_err("Unexpected apdu_reader pipe on host %x\n", 223 pr_err("Unexpected apdu_reader pipe on host %x\n",
224 dm_pipe_info->src_host_id); 224 dm_pipe_info->src_host_id);
225 kfree_skb(skb_pipe_info);
225 continue; 226 continue;
226 } 227 }
227 228
@@ -241,13 +242,12 @@ int st_nci_hci_load_session(struct nci_dev *ndev)
241 ndev->hci_dev->pipes[st_nci_gates[j].pipe].host = 242 ndev->hci_dev->pipes[st_nci_gates[j].pipe].host =
242 dm_pipe_info->src_host_id; 243 dm_pipe_info->src_host_id;
243 } 244 }
245 kfree_skb(skb_pipe_info);
244 } 246 }
245 247
246 memcpy(ndev->hci_dev->init_data.gates, st_nci_gates, 248 memcpy(ndev->hci_dev->init_data.gates, st_nci_gates,
247 sizeof(st_nci_gates)); 249 sizeof(st_nci_gates));
248 250
249free_info:
250 kfree_skb(skb_pipe_info);
251 kfree_skb(skb_pipe_list); 251 kfree_skb(skb_pipe_list);
252 return r; 252 return r;
253} 253}
diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c
index d251f7229c4e..051286562fab 100644
--- a/drivers/nfc/st21nfca/st21nfca.c
+++ b/drivers/nfc/st21nfca/st21nfca.c
@@ -148,14 +148,14 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
148 ST21NFCA_DEVICE_MGNT_GATE, 148 ST21NFCA_DEVICE_MGNT_GATE,
149 ST21NFCA_DEVICE_MGNT_PIPE); 149 ST21NFCA_DEVICE_MGNT_PIPE);
150 if (r < 0) 150 if (r < 0)
151 goto free_info; 151 return r;
152 152
153 /* Get pipe list */ 153 /* Get pipe list */
154 r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE, 154 r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
155 ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list), 155 ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list),
156 &skb_pipe_list); 156 &skb_pipe_list);
157 if (r < 0) 157 if (r < 0)
158 goto free_info; 158 return r;
159 159
160 /* Complete the existing gate_pipe table */ 160 /* Complete the existing gate_pipe table */
161 for (i = 0; i < skb_pipe_list->len; i++) { 161 for (i = 0; i < skb_pipe_list->len; i++) {
@@ -181,6 +181,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
181 info->src_host_id != ST21NFCA_ESE_HOST_ID) { 181 info->src_host_id != ST21NFCA_ESE_HOST_ID) {
182 pr_err("Unexpected apdu_reader pipe on host %x\n", 182 pr_err("Unexpected apdu_reader pipe on host %x\n",
183 info->src_host_id); 183 info->src_host_id);
184 kfree_skb(skb_pipe_info);
184 continue; 185 continue;
185 } 186 }
186 187
@@ -200,6 +201,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
200 hdev->pipes[st21nfca_gates[j].pipe].dest_host = 201 hdev->pipes[st21nfca_gates[j].pipe].dest_host =
201 info->src_host_id; 202 info->src_host_id;
202 } 203 }
204 kfree_skb(skb_pipe_info);
203 } 205 }
204 206
205 /* 207 /*
@@ -214,13 +216,12 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
214 st21nfca_gates[i].gate, 216 st21nfca_gates[i].gate,
215 st21nfca_gates[i].pipe); 217 st21nfca_gates[i].pipe);
216 if (r < 0) 218 if (r < 0)
217 goto free_info; 219 goto free_list;
218 } 220 }
219 } 221 }
220 222
221 memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates)); 223 memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
222free_info: 224free_list:
223 kfree_skb(skb_pipe_info);
224 kfree_skb(skb_pipe_list); 225 kfree_skb(skb_pipe_list);
225 return r; 226 return r;
226} 227}
diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c
index 85b4d86772d8..70b0707fd9a9 100644
--- a/drivers/nfc/trf7970a.c
+++ b/drivers/nfc/trf7970a.c
@@ -336,7 +336,7 @@
336 336
337#define TRF7970A_NFC_TARGET_LEVEL_RFDET(v) ((v) & 0x07) 337#define TRF7970A_NFC_TARGET_LEVEL_RFDET(v) ((v) & 0x07)
338#define TRF7970A_NFC_TARGET_LEVEL_HI_RF BIT(3) 338#define TRF7970A_NFC_TARGET_LEVEL_HI_RF BIT(3)
339#define TRF7970A_NFC_TARGET_LEVEL_SDD_EN BIT(3) 339#define TRF7970A_NFC_TARGET_LEVEL_SDD_EN BIT(5)
340#define TRF7970A_NFC_TARGET_LEVEL_LD_S_4BYTES (0x0 << 6) 340#define TRF7970A_NFC_TARGET_LEVEL_LD_S_4BYTES (0x0 << 6)
341#define TRF7970A_NFC_TARGET_LEVEL_LD_S_7BYTES (0x1 << 6) 341#define TRF7970A_NFC_TARGET_LEVEL_LD_S_7BYTES (0x1 << 6)
342#define TRF7970A_NFC_TARGET_LEVEL_LD_S_10BYTES (0x2 << 6) 342#define TRF7970A_NFC_TARGET_LEVEL_LD_S_10BYTES (0x2 << 6)
@@ -629,7 +629,9 @@ static void trf7970a_send_upstream(struct trf7970a *trf)
629 } 629 }
630 630
631 if (trf->adjust_resp_len) { 631 if (trf->adjust_resp_len) {
632 skb_trim(trf->rx_skb, trf->rx_skb->len - 1); 632 if (trf->rx_skb)
633 skb_trim(trf->rx_skb, trf->rx_skb->len - 1);
634
633 trf->adjust_resp_len = false; 635 trf->adjust_resp_len = false;
634 } 636 }
635 637