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_init(struct s3fwrn5_info
*info
)
25 struct s3fwrn5_fw_info
*fw_info
= &info
->fw_info
;
28 s3fwrn5_fw_init(fw_info
, "sec_s3fwrn5_firmware.bin");
30 /* Get firmware data */
31 ret
= s3fwrn5_fw_request_firmware(fw_info
);
33 dev_err(&fw_info
->ndev
->nfc_dev
->dev
,
34 "Failed to get fw file, ret=%02x\n", ret
);
38 static int s3fwrn5_firmware_update(struct s3fwrn5_info
*info
)
45 s3fwrn5_set_wake(info
, false);
46 s3fwrn5_set_mode(info
, S3FWRN5_MODE_FW
);
48 ret
= s3fwrn5_fw_setup(&info
->fw_info
);
52 need_update
= s3fwrn5_fw_check_version(&info
->fw_info
,
53 info
->ndev
->manufact_specific_info
);
57 dev_info(&info
->ndev
->nfc_dev
->dev
, "Detected new firmware version\n");
59 ret
= s3fwrn5_fw_download(&info
->fw_info
);
63 /* Update RF configuration */
65 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
67 s3fwrn5_set_wake(info
, true);
68 ret
= s3fwrn5_nci_rf_configure(info
, "sec_s3fwrn5_rfreg.bin");
69 s3fwrn5_set_wake(info
, false);
72 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
73 s3fwrn5_fw_cleanup(&info
->fw_info
);
77 static int s3fwrn5_nci_open(struct nci_dev
*ndev
)
79 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
81 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_COLD
)
84 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
85 s3fwrn5_set_wake(info
, true);
90 static int s3fwrn5_nci_close(struct nci_dev
*ndev
)
92 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
94 s3fwrn5_set_wake(info
, false);
95 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
100 static int s3fwrn5_nci_send(struct nci_dev
*ndev
, struct sk_buff
*skb
)
102 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
105 mutex_lock(&info
->mutex
);
107 if (s3fwrn5_get_mode(info
) != S3FWRN5_MODE_NCI
) {
109 mutex_unlock(&info
->mutex
);
113 ret
= s3fwrn5_write(info
, skb
);
116 mutex_unlock(&info
->mutex
);
121 mutex_unlock(&info
->mutex
);
125 static int s3fwrn5_nci_post_setup(struct nci_dev
*ndev
)
127 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
130 if (s3fwrn5_firmware_init(info
)) {
131 //skip bootloader mode
135 ret
= s3fwrn5_firmware_update(info
);
141 s3fwrn5_set_mode(info
, S3FWRN5_MODE_NCI
);
142 s3fwrn5_set_wake(info
, true);
144 ret
= nci_core_reset(info
->ndev
);
148 return nci_core_init(info
->ndev
);
151 static const struct nci_ops s3fwrn5_nci_ops
= {
152 .open
= s3fwrn5_nci_open
,
153 .close
= s3fwrn5_nci_close
,
154 .send
= s3fwrn5_nci_send
,
155 .post_setup
= s3fwrn5_nci_post_setup
,
156 .prop_ops
= s3fwrn5_nci_prop_ops
,
157 .n_prop_ops
= ARRAY_SIZE(s3fwrn5_nci_prop_ops
),
160 int s3fwrn5_probe(struct nci_dev
**ndev
, void *phy_id
, struct device
*pdev
,
161 const struct s3fwrn5_phy_ops
*phy_ops
)
163 struct s3fwrn5_info
*info
;
166 info
= devm_kzalloc(pdev
, sizeof(*info
), GFP_KERNEL
);
170 info
->phy_id
= phy_id
;
172 info
->phy_ops
= phy_ops
;
173 mutex_init(&info
->mutex
);
175 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
177 info
->ndev
= nci_allocate_device(&s3fwrn5_nci_ops
,
178 S3FWRN5_NFC_PROTOCOLS
, 0, 0);
182 nci_set_parent_dev(info
->ndev
, pdev
);
183 nci_set_drvdata(info
->ndev
, info
);
185 ret
= nci_register_device(info
->ndev
);
187 nci_free_device(info
->ndev
);
191 info
->fw_info
.ndev
= info
->ndev
;
197 EXPORT_SYMBOL(s3fwrn5_probe
);
199 void s3fwrn5_remove(struct nci_dev
*ndev
)
201 struct s3fwrn5_info
*info
= nci_get_drvdata(ndev
);
203 s3fwrn5_set_mode(info
, S3FWRN5_MODE_COLD
);
205 nci_unregister_device(ndev
);
206 nci_free_device(ndev
);
208 EXPORT_SYMBOL(s3fwrn5_remove
);
210 int s3fwrn5_recv_frame(struct nci_dev
*ndev
, struct sk_buff
*skb
,
211 enum s3fwrn5_mode mode
)
214 case S3FWRN5_MODE_NCI
:
215 return nci_recv_frame(ndev
, skb
);
216 case S3FWRN5_MODE_FW
:
217 return s3fwrn5_fw_recv_frame(ndev
, skb
);
223 EXPORT_SYMBOL(s3fwrn5_recv_frame
);
225 MODULE_LICENSE("GPL");
226 MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
227 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");