1/*
2 * Marvell NFC driver: major functions
3 *
4 * Copyright (C) 2014, Marvell International Ltd.
5 *
6 * This software file (the "File") is distributed by Marvell International
7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991
8 * (the "License").  You may use, redistribute and/or modify this File in
9 * accordance with the terms and conditions of the License, a copy of which
10 * is available on the worldwide web at
11 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
12 *
13 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
14 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
15 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
16 * this warranty disclaimer.
17 */
18
19#include <linux/module.h>
20#include <linux/nfc.h>
21#include <net/nfc/nci.h>
22#include <net/nfc/nci_core.h>
23#include "nfcmrvl.h"
24
25#define VERSION "1.0"
26
27static int nfcmrvl_nci_open(struct nci_dev *ndev)
28{
29	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
30	int err;
31
32	if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
33		return 0;
34
35	err = priv->if_ops->nci_open(priv);
36
37	if (err)
38		clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags);
39
40	return err;
41}
42
43static int nfcmrvl_nci_close(struct nci_dev *ndev)
44{
45	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
46
47	if (!test_and_clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
48		return 0;
49
50	priv->if_ops->nci_close(priv);
51
52	return 0;
53}
54
55static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
56{
57	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
58
59	nfc_info(priv->dev, "send entry, len %d\n", skb->len);
60
61	skb->dev = (void *)ndev;
62
63	if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
64		return -EBUSY;
65
66	return priv->if_ops->nci_send(priv, skb);
67}
68
69static int nfcmrvl_nci_setup(struct nci_dev *ndev)
70{
71	__u8 val;
72
73	val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
74	nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
75	val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
76	nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
77	val = NFCMRVL_EXT_COEX_ENABLE;
78	nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
79
80	return 0;
81}
82
83static struct nci_ops nfcmrvl_nci_ops = {
84	.open = nfcmrvl_nci_open,
85	.close = nfcmrvl_nci_close,
86	.send = nfcmrvl_nci_send,
87	.setup = nfcmrvl_nci_setup,
88};
89
90struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
91						 struct nfcmrvl_if_ops *ops,
92						 struct device *dev)
93{
94	struct nfcmrvl_private *priv;
95	int rc;
96	u32 protocols;
97
98	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
99	if (!priv)
100		return ERR_PTR(-ENOMEM);
101
102	priv->drv_data = drv_data;
103	priv->if_ops = ops;
104	priv->dev = dev;
105
106	protocols = NFC_PROTO_JEWEL_MASK
107		| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
108		| NFC_PROTO_ISO14443_MASK
109		| NFC_PROTO_ISO14443_B_MASK
110		| NFC_PROTO_NFC_DEP_MASK;
111
112	priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
113	if (!priv->ndev) {
114		nfc_err(dev, "nci_allocate_device failed");
115		rc = -ENOMEM;
116		goto error;
117	}
118
119	nci_set_drvdata(priv->ndev, priv);
120
121	rc = nci_register_device(priv->ndev);
122	if (rc) {
123		nfc_err(dev, "nci_register_device failed %d", rc);
124		nci_free_device(priv->ndev);
125		goto error;
126	}
127
128	nfc_info(dev, "registered with nci successfully\n");
129	return priv;
130
131error:
132	kfree(priv);
133	return ERR_PTR(rc);
134}
135EXPORT_SYMBOL_GPL(nfcmrvl_nci_register_dev);
136
137void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
138{
139	struct nci_dev *ndev = priv->ndev;
140
141	nci_unregister_device(ndev);
142	nci_free_device(ndev);
143	kfree(priv);
144}
145EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
146
147int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
148{
149	struct sk_buff *skb;
150
151	skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
152	if (!skb)
153		return -ENOMEM;
154
155	memcpy(skb_put(skb, count), data, count);
156	nci_recv_frame(priv->ndev, skb);
157
158	return count;
159}
160EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
161
162MODULE_AUTHOR("Marvell International Ltd.");
163MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
164MODULE_VERSION(VERSION);
165MODULE_LICENSE("GPL v2");
166