root/drivers/nfc/s3fwrn5/core.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. s3fwrn5_firmware_update
  2. s3fwrn5_nci_open
  3. s3fwrn5_nci_close
  4. s3fwrn5_nci_send
  5. s3fwrn5_nci_post_setup
  6. s3fwrn5_probe
  7. s3fwrn5_remove
  8. s3fwrn5_recv_frame

   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_update(struct s3fwrn5_info *info)
  24 {
  25         bool need_update;
  26         int ret;
  27 
  28         s3fwrn5_fw_init(&info->fw_info, "sec_s3fwrn5_firmware.bin");
  29 
  30         /* Update firmware */
  31 
  32         s3fwrn5_set_wake(info, false);
  33         s3fwrn5_set_mode(info, S3FWRN5_MODE_FW);
  34 
  35         ret = s3fwrn5_fw_setup(&info->fw_info);
  36         if (ret < 0)
  37                 return ret;
  38 
  39         need_update = s3fwrn5_fw_check_version(&info->fw_info,
  40                 info->ndev->manufact_specific_info);
  41         if (!need_update)
  42                 goto out;
  43 
  44         dev_info(&info->ndev->nfc_dev->dev, "Detected new firmware version\n");
  45 
  46         ret = s3fwrn5_fw_download(&info->fw_info);
  47         if (ret < 0)
  48                 goto out;
  49 
  50         /* Update RF configuration */
  51 
  52         s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
  53 
  54         s3fwrn5_set_wake(info, true);
  55         ret = s3fwrn5_nci_rf_configure(info, "sec_s3fwrn5_rfreg.bin");
  56         s3fwrn5_set_wake(info, false);
  57 
  58 out:
  59         s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
  60         s3fwrn5_fw_cleanup(&info->fw_info);
  61         return ret;
  62 }
  63 
  64 static int s3fwrn5_nci_open(struct nci_dev *ndev)
  65 {
  66         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
  67 
  68         if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_COLD)
  69                 return  -EBUSY;
  70 
  71         s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
  72         s3fwrn5_set_wake(info, true);
  73 
  74         return 0;
  75 }
  76 
  77 static int s3fwrn5_nci_close(struct nci_dev *ndev)
  78 {
  79         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
  80 
  81         s3fwrn5_set_wake(info, false);
  82         s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
  83 
  84         return 0;
  85 }
  86 
  87 static int s3fwrn5_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
  88 {
  89         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
  90         int ret;
  91 
  92         mutex_lock(&info->mutex);
  93 
  94         if (s3fwrn5_get_mode(info) != S3FWRN5_MODE_NCI) {
  95                 mutex_unlock(&info->mutex);
  96                 return -EINVAL;
  97         }
  98 
  99         ret = s3fwrn5_write(info, skb);
 100         if (ret < 0)
 101                 kfree_skb(skb);
 102 
 103         mutex_unlock(&info->mutex);
 104         return ret;
 105 }
 106 
 107 static int s3fwrn5_nci_post_setup(struct nci_dev *ndev)
 108 {
 109         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
 110         int ret;
 111 
 112         ret = s3fwrn5_firmware_update(info);
 113         if (ret < 0)
 114                 goto out;
 115 
 116         /* NCI core reset */
 117 
 118         s3fwrn5_set_mode(info, S3FWRN5_MODE_NCI);
 119         s3fwrn5_set_wake(info, true);
 120 
 121         ret = nci_core_reset(info->ndev);
 122         if (ret < 0)
 123                 goto out;
 124 
 125         ret = nci_core_init(info->ndev);
 126 
 127 out:
 128         return ret;
 129 }
 130 
 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,
 136 };
 137 
 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)
 140 {
 141         struct s3fwrn5_info *info;
 142         int ret;
 143 
 144         info = devm_kzalloc(pdev, sizeof(*info), GFP_KERNEL);
 145         if (!info)
 146                 return -ENOMEM;
 147 
 148         info->phy_id = phy_id;
 149         info->pdev = pdev;
 150         info->phy_ops = phy_ops;
 151         info->max_payload = max_payload;
 152         mutex_init(&info->mutex);
 153 
 154         s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
 155 
 156         s3fwrn5_nci_get_prop_ops(&s3fwrn5_nci_ops.prop_ops,
 157                 &s3fwrn5_nci_ops.n_prop_ops);
 158 
 159         info->ndev = nci_allocate_device(&s3fwrn5_nci_ops,
 160                 S3FWRN5_NFC_PROTOCOLS, 0, 0);
 161         if (!info->ndev)
 162                 return -ENOMEM;
 163 
 164         nci_set_parent_dev(info->ndev, pdev);
 165         nci_set_drvdata(info->ndev, info);
 166 
 167         ret = nci_register_device(info->ndev);
 168         if (ret < 0) {
 169                 nci_free_device(info->ndev);
 170                 return ret;
 171         }
 172 
 173         info->fw_info.ndev = info->ndev;
 174 
 175         *ndev = info->ndev;
 176 
 177         return ret;
 178 }
 179 EXPORT_SYMBOL(s3fwrn5_probe);
 180 
 181 void s3fwrn5_remove(struct nci_dev *ndev)
 182 {
 183         struct s3fwrn5_info *info = nci_get_drvdata(ndev);
 184 
 185         s3fwrn5_set_mode(info, S3FWRN5_MODE_COLD);
 186 
 187         nci_unregister_device(ndev);
 188         nci_free_device(ndev);
 189 }
 190 EXPORT_SYMBOL(s3fwrn5_remove);
 191 
 192 int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,
 193         enum s3fwrn5_mode mode)
 194 {
 195         switch (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);
 200         default:
 201                 return -ENODEV;
 202         }
 203 }
 204 EXPORT_SYMBOL(s3fwrn5_recv_frame);
 205 
 206 MODULE_LICENSE("GPL");
 207 MODULE_DESCRIPTION("Samsung S3FWRN5 NFC driver");
 208 MODULE_AUTHOR("Robert Baldyga <r.baldyga@samsung.com>");

/* [<][>][^][v][top][bottom][index][help] */