2 * NCI based driver for Samsung S3FWRN5 NFC chip
4 * Copyright (C) 2015 Samsung Electrnoics
5 * Robert Baldyga <r.baldyga@samsung.com>
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.
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.
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/>.
20 #include <linux/module.h>
21 #include <net/nfc/nci_core.h>
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)
34 static int s3fwrn5_firmware_update(struct s3fwrn5_info
*info
)
39 s3fwrn5_fw_init(&info
->fw_info
, "sec_s3fwrn5_firmware.bin");
43 s3fwrn5_set_wake(info
, false);
44 s3fwrn5_set_mode(info
, S3FWRN5_MODE_FW
);
46 ret
= s3fwrn5_fw_setup(&info
->fw_info
);
50 need_update
= s3fwrn5_fw_check_version(&info
->fw_info
,
51 info
->ndev
->manufact_specific_info
);
55 dev_info(&info
->ndev
->nfc_dev
->dev
, "Detected new firmware version\n");
57 ret
= s3fwrn5_fw_download(&info
->fw_info
);
61 /* Update RF configuration */
63 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
65 s3fwrn5_set_wake(info
, true);
66 ret
= s3fwrn5_nci_rf_configure(info
, "sec_s3fwrn5_rfreg.bin");
67 s3fwrn5_set_wake(info
, false);
70 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
71 s3fwrn5_fw_cleanup(&info
->fw_info
);
75 static int s3fwrn5_nci_open(struct nci_dev
*ndev
)
77 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
79 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_COLD
)
82 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
83 s3fwrn5_set_wake(info
, true);
88 static int s3fwrn5_nci_close(struct nci_dev
*ndev
)
90 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
92 s3fwrn5_set_wake(info
, false);
93 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
98 static int s3fwrn5_nci_send(struct nci_dev
*ndev
, struct sk_buff
*skb
)
100 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
103 mutex_lock(&info
->mutex
);
105 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_NCI
) {
106 mutex_unlock(&info
->mutex
);
110 ret
= s3fwrn5_write(info
, skb
);
114 mutex_unlock(&info
->mutex
);
118 static int s3fwrn5_nci_post_setup(struct nci_dev
*ndev
)
120 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
123 ret
= s3fwrn5_firmware_update(info
);
129 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
130 s3fwrn5_set_wake(info
, true);
132 ret
= nci_core_reset(info
->ndev
);
136 ret
= nci_core_init(info
->ndev
);
142 static 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
,
149 int s3fwrn5_probe(struct nci_dev
**ndev
, void *phy_id
, struct device
*pdev
,
150 const struct s3fwrn5_phy_ops
*phy_ops
, unsigned int max_payload
)
152 struct s3fwrn5_info
*info
;
155 info
= devm_kzalloc(pdev
, sizeof(*info
), GFP_KERNEL
);
159 info
->phy_id
= phy_id
;
161 info
->phy_ops
= phy_ops
;
162 info
->max_payload
= max_payload
;
163 mutex_init(&info
->mutex
);
165 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
167 s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops
.prop_ops
,
168 &s3fwrn5_nci_ops
.n_prop_ops
);
170 info
->ndev
= nci_allocate_device(&s3fwrn5_nci_ops
,
171 S3FWRN5_NFC_PROTOCOLS
, 0, 0);
175 nci_set_parent_dev(info
->ndev
, pdev
);
176 nci_set_drvdata(info
->ndev
, info
);
178 ret
= nci_register_device(info
->ndev
);
180 nci_free_device(info
->ndev
);
184 info
->fw_info
.ndev
= info
->ndev
;
190 EXPORT_SYMBOL(s3fwrn5_probe
);
192 void s3fwrn5_remove(struct nci_dev
*ndev
)
194 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
196 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
198 nci_unregister_device(ndev
);
199 nci_free_device(ndev
);
201 EXPORT_SYMBOL(s3fwrn5_remove
);
203 int s3fwrn5_recv_frame(struct nci_dev
*ndev
, struct sk_buff
*skb
,
204 enum s3fwrn5_mode 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
);
215 EXPORT_SYMBOL(s3fwrn5_recv_frame
);
217 MODULE_LICENSE("GPL");
218 MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
219 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");