1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * NCI based driver for Samsung S3FWRN5 NFC chip
5 * Copyright (C) 2015 Samsung Electrnoics
6 * Robert Baldyga <r.baldyga@samsung.com>
9 #include <linux/module.h>
10 #include <net/nfc/nci_core.h>
16 #define S3FWRN5_NFC_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
17 NFC_PROTO_MIFARE_MASK | \
18 NFC_PROTO_FELICA_MASK | \
19 NFC_PROTO_ISO14443_MASK | \
20 NFC_PROTO_ISO14443_B_MASK | \
21 NFC_PROTO_ISO15693_MASK)
23 static int s3fwrn5_firmware_update(struct s3fwrn5_info
*info
)
28 s3fwrn5_fw_init(&info
->fw_info
, "sec_s3fwrn5_firmware.bin");
32 s3fwrn5_set_wake(info
, false);
33 s3fwrn5_set_mode(info
, S3FWRN5_MODE_FW
);
35 ret
= s3fwrn5_fw_setup(&info
->fw_info
);
39 need_update
= s3fwrn5_fw_check_version(&info
->fw_info
,
40 info
->ndev
->manufact_specific_info
);
44 dev_info(&info
->ndev
->nfc_dev
->dev
, "Detected new firmware version\n");
46 ret
= s3fwrn5_fw_download(&info
->fw_info
);
50 /* Update RF configuration */
52 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
54 s3fwrn5_set_wake(info
, true);
55 ret
= s3fwrn5_nci_rf_configure(info
, "sec_s3fwrn5_rfreg.bin");
56 s3fwrn5_set_wake(info
, false);
59 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
60 s3fwrn5_fw_cleanup(&info
->fw_info
);
64 static int s3fwrn5_nci_open(struct nci_dev
*ndev
)
66 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
68 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_COLD
)
71 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
72 s3fwrn5_set_wake(info
, true);
77 static int s3fwrn5_nci_close(struct nci_dev
*ndev
)
79 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
81 s3fwrn5_set_wake(info
, false);
82 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
87 static int s3fwrn5_nci_send(struct nci_dev
*ndev
, struct sk_buff
*skb
)
89 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
92 mutex_lock(&info
->mutex
);
94 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_NCI
) {
95 mutex_unlock(&info
->mutex
);
99 ret
= s3fwrn5_write(info
, skb
);
103 mutex_unlock(&info
->mutex
);
107 static int s3fwrn5_nci_post_setup(struct nci_dev
*ndev
)
109 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
112 ret
= s3fwrn5_firmware_update(info
);
118 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
119 s3fwrn5_set_wake(info
, true);
121 ret
= nci_core_reset(info
->ndev
);
125 ret
= nci_core_init(info
->ndev
);
131 static struct nci_ops s3fwrn5_nci_ops
= {
132 .open
= s3fwrn5_nci_open
,
133 .close
= s3fwrn5_nci_close
,
134 .send
= s3fwrn5_nci_send
,
135 .post_setup
= s3fwrn5_nci_post_setup
,
138 int s3fwrn5_probe(struct nci_dev
**ndev
, void *phy_id
, struct device
*pdev
,
139 const struct s3fwrn5_phy_ops
*phy_ops
, unsigned int max_payload
)
141 struct s3fwrn5_info
*info
;
144 info
= devm_kzalloc(pdev
, sizeof(*info
), GFP_KERNEL
);
148 info
->phy_id
= phy_id
;
150 info
->phy_ops
= phy_ops
;
151 info
->max_payload
= max_payload
;
152 mutex_init(&info
->mutex
);
154 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
156 s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops
.prop_ops
,
157 &s3fwrn5_nci_ops
.n_prop_ops
);
159 info
->ndev
= nci_allocate_device(&s3fwrn5_nci_ops
,
160 S3FWRN5_NFC_PROTOCOLS
, 0, 0);
164 nci_set_parent_dev(info
->ndev
, pdev
);
165 nci_set_drvdata(info
->ndev
, info
);
167 ret
= nci_register_device(info
->ndev
);
169 nci_free_device(info
->ndev
);
173 info
->fw_info
.ndev
= info
->ndev
;
179 EXPORT_SYMBOL(s3fwrn5_probe
);
181 void s3fwrn5_remove(struct nci_dev
*ndev
)
183 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
185 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
187 nci_unregister_device(ndev
);
188 nci_free_device(ndev
);
190 EXPORT_SYMBOL(s3fwrn5_remove
);
192 int s3fwrn5_recv_frame(struct nci_dev
*ndev
, struct sk_buff
*skb
,
193 enum s3fwrn5_mode mode
)
196 case S3FWRN5_MODE_NCI
:
197 return nci_recv_frame(ndev
, skb
);
198 case S3FWRN5_MODE_FW
:
199 return s3fwrn5_fw_recv_frame(ndev
, skb
);
204 EXPORT_SYMBOL(s3fwrn5_recv_frame
);
206 MODULE_LICENSE("GPL");
207 MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
208 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");