1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * NCI based driver for Samsung S3FWRN5 NFC chip 4 * 5 * Copyright (C) 2015 Samsung Electrnoics 6 * Robert Baldyga <r.baldyga@samsung.com> 7 */ 8 9 #include <linux/module.h> 10 #include <net/nfc/nci_core.h> 11 12 #include "s3fwrn5.h" 13 #include "firmware.h" 14 #include "nci.h" 15 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) 22 23 static int s3fwrn5_firmware_init(struct s3fwrn5_info *info) 24 { 25 struct s3fwrn5_fw_info *fw_info = &info->fw_info; 26 int ret; 27 28 s3fwrn5_fw_init(fw_info, "sec_s3fwrn5_firmware.bin"); 29 30 /* Get firmware data */ 31 ret = s3fwrn5_fw_request_firmware(fw_info); 32 if (ret < 0) 33 dev_err(&fw_info->ndev->nfc_dev->dev, 34 "Failed to get fw file, ret=%02x\n", ret); 35 return ret; 36 } 37 38 static int s3fwrn5_firmware_update(struct s3fwrn5_info *info) 39 { 40 bool need_update; 41 int ret; 42 43 /* Update firmware */ 44 45 s3fwrn5_set_wake(info, false); 46 s3fwrn5_set_mode(info, S3FWRN5_MODE_FW); 47 48 ret = s3fwrn5_fw_setup(&info->fw_info); 49 if (ret < 0) 50 return ret; 51 52 need_update = s3fwrn5_fw_check_version(&info->fw_info, 53 info->ndev->manufact_specific_info); 54 if (!need_update) 55 goto out; 56 57 dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n"); 58 59 ret = s3fwrn5_fw_download(&info->fw_info); 60 if (ret < 0) 61 goto out; 62 63 /* Update RF configuration */ 64 65 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 66 67 s3fwrn5_set_wake(info, true); 68 ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin"); 69 s3fwrn5_set_wake(info, false); 70 71 out: 72 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 73 s3fwrn5_fw_cleanup(&info->fw_info); 74 return ret; 75 } 76 77 static int s3fwrn5_nci_open(struct nci_dev *ndev) 78 { 79 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 80 81 if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD) 82 return -EBUSY; 83 84 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 85 s3fwrn5_set_wake(info, true); 86 87 return 0; 88 } 89 90 static int s3fwrn5_nci_close(struct nci_dev *ndev) 91 { 92 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 93 94 s3fwrn5_set_wake(info, false); 95 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 96 97 return 0; 98 } 99 100 static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb) 101 { 102 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 103 int ret; 104 105 mutex_lock(&info->mutex); 106 107 if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) { 108 kfree_skb(skb); 109 mutex_unlock(&info->mutex); 110 return -EINVAL; 111 } 112 113 ret = s3fwrn5_write(info, skb); 114 if (ret < 0) { 115 kfree_skb(skb); 116 mutex_unlock(&info->mutex); 117 return ret; 118 } 119 120 consume_skb(skb); 121 mutex_unlock(&info->mutex); 122 return 0; 123 } 124 125 static int s3fwrn5_nci_post_setup(struct nci_dev *ndev) 126 { 127 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 128 int ret; 129 130 if (s3fwrn5_firmware_init(info)) { 131 //skip bootloader mode 132 return 0; 133 } 134 135 ret = s3fwrn5_firmware_update(info); 136 if (ret < 0) 137 return ret; 138 139 /* NCI core reset */ 140 141 s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI); 142 s3fwrn5_set_wake(info, true); 143 144 ret = nci_core_reset(info->ndev); 145 if (ret < 0) 146 return ret; 147 148 return nci_core_init(info->ndev); 149 } 150 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), 158 }; 159 160 int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev, 161 const struct s3fwrn5_phy_ops *phy_ops) 162 { 163 struct s3fwrn5_info *info; 164 int ret; 165 166 info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL); 167 if (!info) 168 return -ENOMEM; 169 170 info->phy_id = phy_id; 171 info->pdev = pdev; 172 info->phy_ops = phy_ops; 173 mutex_init(&info->mutex); 174 175 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 176 177 info->ndev = nci_allocate_device(&s3fwrn5_nci_ops, 178 S3FWRN5_NFC_PROTOCOLS, 0, 0); 179 if (!info->ndev) 180 return -ENOMEM; 181 182 nci_set_parent_dev(info->ndev, pdev); 183 nci_set_drvdata(info->ndev, info); 184 185 ret = nci_register_device(info->ndev); 186 if (ret < 0) { 187 nci_free_device(info->ndev); 188 return ret; 189 } 190 191 info->fw_info.ndev = info->ndev; 192 193 *ndev = info->ndev; 194 195 return ret; 196 } 197 EXPORT_SYMBOL(s3fwrn5_probe); 198 199 void s3fwrn5_remove(struct nci_dev *ndev) 200 { 201 struct s3fwrn5_info *info = nci_get_drvdata(ndev); 202 203 s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD); 204 205 nci_unregister_device(ndev); 206 nci_free_device(ndev); 207 } 208 EXPORT_SYMBOL(s3fwrn5_remove); 209 210 int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb, 211 enum s3fwrn5_mode mode) 212 { 213 switch (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); 218 default: 219 kfree_skb(skb); 220 return -ENODEV; 221 } 222 } 223 EXPORT_SYMBOL(s3fwrn5_recv_frame); 224 225 MODULE_LICENSE("GPL"); 226 MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver"); 227 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>"); 228