st21nfcb.c 3.13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * NCI based Driver for STMicroelectronics NFC Chip
 *
 * Copyright (C) 2014  STMicroelectronics SAS. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include <linux/module.h>
#include <linux/nfc.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>

#include "st21nfcb.h"

#define DRIVER_DESC "NCI NFC driver for ST21NFCB"

28 29
#define ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 0x83

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
static int st21nfcb_nci_open(struct nci_dev *ndev)
{
	struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
	int r;

	if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags))
		return 0;

	r = ndlc_open(info->ndlc);
	if (r)
		clear_bit(ST21NFCB_NCI_RUNNING, &info->flags);

	return r;
}

static int st21nfcb_nci_close(struct nci_dev *ndev)
{
	struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);

	if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags))
		return 0;

	ndlc_close(info->ndlc);

	return 0;
}

static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
{
	struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);

	skb->dev = (void *)ndev;

	if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags))
		return -EBUSY;

	return ndlc_send(info->ndlc, skb);
}

69 70 71 72 73 74 75
static __u32 st21nfcb_nci_get_rfprotocol(struct nci_dev *ndev,
					 __u8 rf_protocol)
{
	return rf_protocol == ST21NFCB_NCI1_X_PROPRIETARY_ISO15693 ?
		NFC_PROTO_ISO15693_MASK : 0;
}

76 77 78 79
static struct nci_ops st21nfcb_nci_ops = {
	.open = st21nfcb_nci_open,
	.close = st21nfcb_nci_close,
	.send = st21nfcb_nci_send,
80
	.get_rfprotocol = st21nfcb_nci_get_rfprotocol,
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
};

int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
		       int phy_tailroom)
{
	struct st21nfcb_nci_info *info;
	int r;
	u32 protocols;

	info = devm_kzalloc(ndlc->dev,
			sizeof(struct st21nfcb_nci_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	protocols = NFC_PROTO_JEWEL_MASK
		| NFC_PROTO_MIFARE_MASK
		| NFC_PROTO_FELICA_MASK
		| NFC_PROTO_ISO14443_MASK
		| NFC_PROTO_ISO14443_B_MASK
100
		| NFC_PROTO_ISO15693_MASK
101 102 103 104 105 106
		| NFC_PROTO_NFC_DEP_MASK;

	ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
					phy_headroom, phy_tailroom);
	if (!ndlc->ndev) {
		pr_err("Cannot allocate nfc ndev\n");
107
		return -ENOMEM;
108 109 110 111 112 113
	}
	info->ndlc = ndlc;

	nci_set_drvdata(ndlc->ndev, info);

	r = nci_register_device(ndlc->ndev);
114 115 116 117
	if (r) {
		pr_err("Cannot register nfc device to nci core\n");
		nci_free_device(ndlc->ndev);
	}
118 119 120 121 122 123 124 125 126 127 128 129 130 131

	return r;
}
EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);

void st21nfcb_nci_remove(struct nci_dev *ndev)
{
	nci_unregister_device(ndev);
	nci_free_device(ndev);
}
EXPORT_SYMBOL_GPL(st21nfcb_nci_remove);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);