xref: /linux/drivers/nfc/pn544/pn544.c (revision 27c31191b3d7ff32c266a5dbea344b9aa96ebf14)
197f18414SEric Lapuyade /*
297f18414SEric Lapuyade  * HCI based Driver for NXP PN544 NFC Chip
397f18414SEric Lapuyade  *
497f18414SEric Lapuyade  * Copyright (C) 2012  Intel Corporation. All rights reserved.
597f18414SEric Lapuyade  *
697f18414SEric Lapuyade  * This program is free software; you can redistribute it and/or modify it
797f18414SEric Lapuyade  * under the terms and conditions of the GNU General Public License,
897f18414SEric Lapuyade  * version 2, as published by the Free Software Foundation.
997f18414SEric Lapuyade  *
1097f18414SEric Lapuyade  * This program is distributed in the hope that it will be useful,
1197f18414SEric Lapuyade  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1297f18414SEric Lapuyade  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1397f18414SEric Lapuyade  * GNU General Public License for more details.
1497f18414SEric Lapuyade  *
1597f18414SEric Lapuyade  * You should have received a copy of the GNU General Public License
1697f18414SEric Lapuyade  * along with this program; if not, write to the
1797f18414SEric Lapuyade  * Free Software Foundation, Inc.,
1897f18414SEric Lapuyade  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
1997f18414SEric Lapuyade  */
2097f18414SEric Lapuyade 
2197f18414SEric Lapuyade #include <linux/delay.h>
2297f18414SEric Lapuyade #include <linux/slab.h>
2397f18414SEric Lapuyade 
2497f18414SEric Lapuyade #include <linux/nfc.h>
2597f18414SEric Lapuyade #include <net/nfc/hci.h>
2697f18414SEric Lapuyade #include <net/nfc/llc.h>
2797f18414SEric Lapuyade 
2897f18414SEric Lapuyade #include "pn544.h"
2997f18414SEric Lapuyade 
3097f18414SEric Lapuyade /* Timing restrictions (ms) */
3197f18414SEric Lapuyade #define PN544_HCI_RESETVEN_TIME		30
3297f18414SEric Lapuyade 
3397f18414SEric Lapuyade #define HCI_MODE 0
3497f18414SEric Lapuyade #define FW_MODE 1
3597f18414SEric Lapuyade 
3697f18414SEric Lapuyade enum pn544_state {
3797f18414SEric Lapuyade 	PN544_ST_COLD,
3897f18414SEric Lapuyade 	PN544_ST_FW_READY,
3997f18414SEric Lapuyade 	PN544_ST_READY,
4097f18414SEric Lapuyade };
4197f18414SEric Lapuyade 
4297f18414SEric Lapuyade #define FULL_VERSION_LEN 11
4397f18414SEric Lapuyade 
4497f18414SEric Lapuyade /* Proprietary commands */
4597f18414SEric Lapuyade #define PN544_WRITE		0x3f
4697f18414SEric Lapuyade 
4797f18414SEric Lapuyade /* Proprietary gates, events, commands and registers */
4897f18414SEric Lapuyade 
4997f18414SEric Lapuyade /* NFC_HCI_RF_READER_A_GATE additional registers and commands */
5097f18414SEric Lapuyade #define PN544_RF_READER_A_AUTO_ACTIVATION			0x10
5197f18414SEric Lapuyade #define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION		0x12
5297f18414SEric Lapuyade #define PN544_MIFARE_CMD					0x21
5397f18414SEric Lapuyade 
5497f18414SEric Lapuyade /* Commands that apply to all RF readers */
5597f18414SEric Lapuyade #define PN544_RF_READER_CMD_PRESENCE_CHECK	0x30
5697f18414SEric Lapuyade #define PN544_RF_READER_CMD_ACTIVATE_NEXT	0x32
5797f18414SEric Lapuyade 
5897f18414SEric Lapuyade /* NFC_HCI_ID_MGMT_GATE additional registers */
5997f18414SEric Lapuyade #define PN544_ID_MGMT_FULL_VERSION_SW		0x10
6097f18414SEric Lapuyade 
6197f18414SEric Lapuyade #define PN544_RF_READER_ISO15693_GATE		0x12
6297f18414SEric Lapuyade 
6397f18414SEric Lapuyade #define PN544_RF_READER_F_GATE			0x14
6497f18414SEric Lapuyade #define PN544_FELICA_ID				0x04
6597f18414SEric Lapuyade #define PN544_FELICA_RAW			0x20
6697f18414SEric Lapuyade 
6797f18414SEric Lapuyade #define PN544_RF_READER_JEWEL_GATE		0x15
6897f18414SEric Lapuyade #define PN544_JEWEL_RAW_CMD			0x23
6997f18414SEric Lapuyade 
7097f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_INITIATOR_GATE	0x30
7197f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_TARGET_GATE	0x31
7297f18414SEric Lapuyade 
7397f18414SEric Lapuyade #define PN544_SYS_MGMT_GATE			0x90
7497f18414SEric Lapuyade #define PN544_SYS_MGMT_INFO_NOTIFICATION	0x02
7597f18414SEric Lapuyade 
7697f18414SEric Lapuyade #define PN544_POLLING_LOOP_MGMT_GATE		0x94
7797f18414SEric Lapuyade #define PN544_DEP_MODE				0x01
7897f18414SEric Lapuyade #define PN544_DEP_ATR_REQ			0x02
7997f18414SEric Lapuyade #define PN544_DEP_ATR_RES			0x03
8097f18414SEric Lapuyade #define PN544_DEP_MERGE				0x0D
8197f18414SEric Lapuyade #define PN544_PL_RDPHASES			0x06
8297f18414SEric Lapuyade #define PN544_PL_EMULATION			0x07
8397f18414SEric Lapuyade #define PN544_PL_NFCT_DEACTIVATED		0x09
8497f18414SEric Lapuyade 
8597f18414SEric Lapuyade #define PN544_SWP_MGMT_GATE			0xA0
8697f18414SEric Lapuyade 
8797f18414SEric Lapuyade #define PN544_NFC_WI_MGMT_GATE			0xA1
8897f18414SEric Lapuyade 
8997f18414SEric Lapuyade #define PN544_HCI_EVT_SND_DATA			0x01
9097f18414SEric Lapuyade #define PN544_HCI_EVT_ACTIVATED			0x02
9197f18414SEric Lapuyade #define PN544_HCI_EVT_DEACTIVATED		0x03
9297f18414SEric Lapuyade #define PN544_HCI_EVT_RCV_DATA			0x04
9397f18414SEric Lapuyade #define PN544_HCI_EVT_CONTINUE_MI		0x05
9497f18414SEric Lapuyade 
9597f18414SEric Lapuyade #define PN544_HCI_CMD_ATTREQUEST		0x12
9697f18414SEric Lapuyade #define PN544_HCI_CMD_CONTINUE_ACTIVATION	0x13
9797f18414SEric Lapuyade 
9897f18414SEric Lapuyade static struct nfc_hci_gate pn544_gates[] = {
9997f18414SEric Lapuyade 	{NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
10097f18414SEric Lapuyade 	{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
10197f18414SEric Lapuyade 	{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10297f18414SEric Lapuyade 	{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10397f18414SEric Lapuyade 	{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
10497f18414SEric Lapuyade 	{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
10597f18414SEric Lapuyade 	{PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10697f18414SEric Lapuyade 	{PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10797f18414SEric Lapuyade 	{PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10897f18414SEric Lapuyade 	{PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE},
10997f18414SEric Lapuyade 	{PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
11097f18414SEric Lapuyade 	{PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE},
11197f18414SEric Lapuyade 	{PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
11297f18414SEric Lapuyade 	{PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE},
11397f18414SEric Lapuyade 	{PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE}
11497f18414SEric Lapuyade };
11597f18414SEric Lapuyade 
11697f18414SEric Lapuyade /* Largest headroom needed for outgoing custom commands */
11797f18414SEric Lapuyade #define PN544_CMDS_HEADROOM	2
11897f18414SEric Lapuyade 
11997f18414SEric Lapuyade struct pn544_hci_info {
12097f18414SEric Lapuyade 	struct nfc_phy_ops *phy_ops;
12197f18414SEric Lapuyade 	void *phy_id;
12297f18414SEric Lapuyade 
12397f18414SEric Lapuyade 	struct nfc_hci_dev *hdev;
12497f18414SEric Lapuyade 
12597f18414SEric Lapuyade 	enum pn544_state state;
12697f18414SEric Lapuyade 
12797f18414SEric Lapuyade 	struct mutex info_lock;
12897f18414SEric Lapuyade 
12997f18414SEric Lapuyade 	int async_cb_type;
13097f18414SEric Lapuyade 	data_exchange_cb_t async_cb;
13197f18414SEric Lapuyade 	void *async_cb_context;
13297f18414SEric Lapuyade };
13397f18414SEric Lapuyade 
13497f18414SEric Lapuyade static int pn544_hci_open(struct nfc_hci_dev *hdev)
13597f18414SEric Lapuyade {
13697f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
13797f18414SEric Lapuyade 	int r = 0;
13897f18414SEric Lapuyade 
13997f18414SEric Lapuyade 	mutex_lock(&info->info_lock);
14097f18414SEric Lapuyade 
14197f18414SEric Lapuyade 	if (info->state != PN544_ST_COLD) {
14297f18414SEric Lapuyade 		r = -EBUSY;
14397f18414SEric Lapuyade 		goto out;
14497f18414SEric Lapuyade 	}
14597f18414SEric Lapuyade 
14697f18414SEric Lapuyade 	r = info->phy_ops->enable(info->phy_id);
14797f18414SEric Lapuyade 
14897f18414SEric Lapuyade 	if (r == 0)
14997f18414SEric Lapuyade 		info->state = PN544_ST_READY;
15097f18414SEric Lapuyade 
15197f18414SEric Lapuyade out:
15297f18414SEric Lapuyade 	mutex_unlock(&info->info_lock);
15397f18414SEric Lapuyade 	return r;
15497f18414SEric Lapuyade }
15597f18414SEric Lapuyade 
15697f18414SEric Lapuyade static void pn544_hci_close(struct nfc_hci_dev *hdev)
15797f18414SEric Lapuyade {
15897f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
15997f18414SEric Lapuyade 
16097f18414SEric Lapuyade 	mutex_lock(&info->info_lock);
16197f18414SEric Lapuyade 
16297f18414SEric Lapuyade 	if (info->state == PN544_ST_COLD)
16397f18414SEric Lapuyade 		goto out;
16497f18414SEric Lapuyade 
16597f18414SEric Lapuyade 	info->phy_ops->disable(info->phy_id);
16697f18414SEric Lapuyade 
16797f18414SEric Lapuyade 	info->state = PN544_ST_COLD;
16897f18414SEric Lapuyade 
16997f18414SEric Lapuyade out:
17097f18414SEric Lapuyade 	mutex_unlock(&info->info_lock);
17197f18414SEric Lapuyade }
17297f18414SEric Lapuyade 
17397f18414SEric Lapuyade static int pn544_hci_ready(struct nfc_hci_dev *hdev)
17497f18414SEric Lapuyade {
17597f18414SEric Lapuyade 	struct sk_buff *skb;
17697f18414SEric Lapuyade 	static struct hw_config {
17797f18414SEric Lapuyade 		u8 adr[2];
17897f18414SEric Lapuyade 		u8 value;
17997f18414SEric Lapuyade 	} hw_config[] = {
18097f18414SEric Lapuyade 		{{0x9f, 0x9a}, 0x00},
18197f18414SEric Lapuyade 
18297f18414SEric Lapuyade 		{{0x98, 0x10}, 0xbc},
18397f18414SEric Lapuyade 
18497f18414SEric Lapuyade 		{{0x9e, 0x71}, 0x00},
18597f18414SEric Lapuyade 
18697f18414SEric Lapuyade 		{{0x98, 0x09}, 0x00},
18797f18414SEric Lapuyade 
18897f18414SEric Lapuyade 		{{0x9e, 0xb4}, 0x00},
18997f18414SEric Lapuyade 
19097f18414SEric Lapuyade 		{{0x9e, 0xd9}, 0xff},
19197f18414SEric Lapuyade 		{{0x9e, 0xda}, 0xff},
19297f18414SEric Lapuyade 		{{0x9e, 0xdb}, 0x23},
19397f18414SEric Lapuyade 		{{0x9e, 0xdc}, 0x21},
19497f18414SEric Lapuyade 		{{0x9e, 0xdd}, 0x22},
19597f18414SEric Lapuyade 		{{0x9e, 0xde}, 0x24},
19697f18414SEric Lapuyade 
19797f18414SEric Lapuyade 		{{0x9c, 0x01}, 0x08},
19897f18414SEric Lapuyade 
19997f18414SEric Lapuyade 		{{0x9e, 0xaa}, 0x01},
20097f18414SEric Lapuyade 
20197f18414SEric Lapuyade 		{{0x9b, 0xd1}, 0x0d},
20297f18414SEric Lapuyade 		{{0x9b, 0xd2}, 0x24},
20397f18414SEric Lapuyade 		{{0x9b, 0xd3}, 0x0a},
20497f18414SEric Lapuyade 		{{0x9b, 0xd4}, 0x22},
20597f18414SEric Lapuyade 		{{0x9b, 0xd5}, 0x08},
20697f18414SEric Lapuyade 		{{0x9b, 0xd6}, 0x1e},
20797f18414SEric Lapuyade 		{{0x9b, 0xdd}, 0x1c},
20897f18414SEric Lapuyade 
20997f18414SEric Lapuyade 		{{0x9b, 0x84}, 0x13},
21097f18414SEric Lapuyade 		{{0x99, 0x81}, 0x7f},
21197f18414SEric Lapuyade 		{{0x99, 0x31}, 0x70},
21297f18414SEric Lapuyade 
21397f18414SEric Lapuyade 		{{0x98, 0x00}, 0x3f},
21497f18414SEric Lapuyade 
21597f18414SEric Lapuyade 		{{0x9f, 0x09}, 0x00},
21697f18414SEric Lapuyade 
21797f18414SEric Lapuyade 		{{0x9f, 0x0a}, 0x05},
21897f18414SEric Lapuyade 
21997f18414SEric Lapuyade 		{{0x9e, 0xd1}, 0xa1},
22097f18414SEric Lapuyade 		{{0x99, 0x23}, 0x00},
22197f18414SEric Lapuyade 
22297f18414SEric Lapuyade 		{{0x9e, 0x74}, 0x80},
22397f18414SEric Lapuyade 
22497f18414SEric Lapuyade 		{{0x9f, 0x28}, 0x10},
22597f18414SEric Lapuyade 
22697f18414SEric Lapuyade 		{{0x9f, 0x35}, 0x14},
22797f18414SEric Lapuyade 
22897f18414SEric Lapuyade 		{{0x9f, 0x36}, 0x60},
22997f18414SEric Lapuyade 
23097f18414SEric Lapuyade 		{{0x9c, 0x31}, 0x00},
23197f18414SEric Lapuyade 
23297f18414SEric Lapuyade 		{{0x9c, 0x32}, 0xc8},
23397f18414SEric Lapuyade 
23497f18414SEric Lapuyade 		{{0x9c, 0x19}, 0x40},
23597f18414SEric Lapuyade 
23697f18414SEric Lapuyade 		{{0x9c, 0x1a}, 0x40},
23797f18414SEric Lapuyade 
23897f18414SEric Lapuyade 		{{0x9c, 0x0c}, 0x00},
23997f18414SEric Lapuyade 
24097f18414SEric Lapuyade 		{{0x9c, 0x0d}, 0x00},
24197f18414SEric Lapuyade 
24297f18414SEric Lapuyade 		{{0x9c, 0x12}, 0x00},
24397f18414SEric Lapuyade 
24497f18414SEric Lapuyade 		{{0x9c, 0x13}, 0x00},
24597f18414SEric Lapuyade 
24697f18414SEric Lapuyade 		{{0x98, 0xa2}, 0x0e},
24797f18414SEric Lapuyade 
24897f18414SEric Lapuyade 		{{0x98, 0x93}, 0x40},
24997f18414SEric Lapuyade 
25097f18414SEric Lapuyade 		{{0x98, 0x7d}, 0x02},
25197f18414SEric Lapuyade 		{{0x98, 0x7e}, 0x00},
25297f18414SEric Lapuyade 		{{0x9f, 0xc8}, 0x01},
25397f18414SEric Lapuyade 	};
25497f18414SEric Lapuyade 	struct hw_config *p = hw_config;
25597f18414SEric Lapuyade 	int count = ARRAY_SIZE(hw_config);
25697f18414SEric Lapuyade 	struct sk_buff *res_skb;
25797f18414SEric Lapuyade 	u8 param[4];
25897f18414SEric Lapuyade 	int r;
25997f18414SEric Lapuyade 
26097f18414SEric Lapuyade 	param[0] = 0;
26197f18414SEric Lapuyade 	while (count--) {
26297f18414SEric Lapuyade 		param[1] = p->adr[0];
26397f18414SEric Lapuyade 		param[2] = p->adr[1];
26497f18414SEric Lapuyade 		param[3] = p->value;
26597f18414SEric Lapuyade 
26697f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE,
26797f18414SEric Lapuyade 				     param, 4, &res_skb);
26897f18414SEric Lapuyade 		if (r < 0)
26997f18414SEric Lapuyade 			return r;
27097f18414SEric Lapuyade 
27197f18414SEric Lapuyade 		if (res_skb->len != 1) {
27297f18414SEric Lapuyade 			kfree_skb(res_skb);
27397f18414SEric Lapuyade 			return -EPROTO;
27497f18414SEric Lapuyade 		}
27597f18414SEric Lapuyade 
27697f18414SEric Lapuyade 		if (res_skb->data[0] != p->value) {
27797f18414SEric Lapuyade 			kfree_skb(res_skb);
27897f18414SEric Lapuyade 			return -EIO;
27997f18414SEric Lapuyade 		}
28097f18414SEric Lapuyade 
28197f18414SEric Lapuyade 		kfree_skb(res_skb);
28297f18414SEric Lapuyade 
28397f18414SEric Lapuyade 		p++;
28497f18414SEric Lapuyade 	}
28597f18414SEric Lapuyade 
28697f18414SEric Lapuyade 	param[0] = NFC_HCI_UICC_HOST_ID;
28797f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
28897f18414SEric Lapuyade 			      NFC_HCI_ADMIN_WHITELIST, param, 1);
28997f18414SEric Lapuyade 	if (r < 0)
29097f18414SEric Lapuyade 		return r;
29197f18414SEric Lapuyade 
29297f18414SEric Lapuyade 	param[0] = 0x3d;
29397f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE,
29497f18414SEric Lapuyade 			      PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1);
29597f18414SEric Lapuyade 	if (r < 0)
29697f18414SEric Lapuyade 		return r;
29797f18414SEric Lapuyade 
29897f18414SEric Lapuyade 	param[0] = 0x0;
29997f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE,
30097f18414SEric Lapuyade 			      PN544_RF_READER_A_AUTO_ACTIVATION, param, 1);
30197f18414SEric Lapuyade 	if (r < 0)
30297f18414SEric Lapuyade 		return r;
30397f18414SEric Lapuyade 
30497f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
30597f18414SEric Lapuyade 			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
30697f18414SEric Lapuyade 	if (r < 0)
30797f18414SEric Lapuyade 		return r;
30897f18414SEric Lapuyade 
30997f18414SEric Lapuyade 	param[0] = 0x1;
31097f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
31197f18414SEric Lapuyade 			      PN544_PL_NFCT_DEACTIVATED, param, 1);
31297f18414SEric Lapuyade 	if (r < 0)
31397f18414SEric Lapuyade 		return r;
31497f18414SEric Lapuyade 
31597f18414SEric Lapuyade 	param[0] = 0x0;
31697f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
31797f18414SEric Lapuyade 			      PN544_PL_RDPHASES, param, 1);
31897f18414SEric Lapuyade 	if (r < 0)
31997f18414SEric Lapuyade 		return r;
32097f18414SEric Lapuyade 
32197f18414SEric Lapuyade 	r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
32297f18414SEric Lapuyade 			      PN544_ID_MGMT_FULL_VERSION_SW, &skb);
32397f18414SEric Lapuyade 	if (r < 0)
32497f18414SEric Lapuyade 		return r;
32597f18414SEric Lapuyade 
32697f18414SEric Lapuyade 	if (skb->len != FULL_VERSION_LEN) {
32797f18414SEric Lapuyade 		kfree_skb(skb);
32897f18414SEric Lapuyade 		return -EINVAL;
32997f18414SEric Lapuyade 	}
33097f18414SEric Lapuyade 
33197f18414SEric Lapuyade 	print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
33297f18414SEric Lapuyade 		       DUMP_PREFIX_NONE, 16, 1,
33397f18414SEric Lapuyade 		       skb->data, FULL_VERSION_LEN, false);
33497f18414SEric Lapuyade 
33597f18414SEric Lapuyade 	kfree_skb(skb);
33697f18414SEric Lapuyade 
33797f18414SEric Lapuyade 	return 0;
33897f18414SEric Lapuyade }
33997f18414SEric Lapuyade 
34097f18414SEric Lapuyade static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
34197f18414SEric Lapuyade {
34297f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
34397f18414SEric Lapuyade 
34497f18414SEric Lapuyade 	return info->phy_ops->write(info->phy_id, skb);
34597f18414SEric Lapuyade }
34697f18414SEric Lapuyade 
34797f18414SEric Lapuyade static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
34897f18414SEric Lapuyade 				u32 im_protocols, u32 tm_protocols)
34997f18414SEric Lapuyade {
35097f18414SEric Lapuyade 	u8 phases = 0;
35197f18414SEric Lapuyade 	int r;
35297f18414SEric Lapuyade 	u8 duration[2];
35397f18414SEric Lapuyade 	u8 activated;
35497f18414SEric Lapuyade 	u8 i_mode = 0x3f; /* Enable all supported modes */
35597f18414SEric Lapuyade 	u8 t_mode = 0x0f;
35697f18414SEric Lapuyade 	u8 t_merge = 0x01; /* Enable merge by default */
35797f18414SEric Lapuyade 
35897f18414SEric Lapuyade 	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
35997f18414SEric Lapuyade 		__func__, im_protocols, tm_protocols);
36097f18414SEric Lapuyade 
36197f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
36297f18414SEric Lapuyade 			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
36397f18414SEric Lapuyade 	if (r < 0)
36497f18414SEric Lapuyade 		return r;
36597f18414SEric Lapuyade 
36697f18414SEric Lapuyade 	duration[0] = 0x18;
36797f18414SEric Lapuyade 	duration[1] = 0x6a;
36897f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
36997f18414SEric Lapuyade 			      PN544_PL_EMULATION, duration, 2);
37097f18414SEric Lapuyade 	if (r < 0)
37197f18414SEric Lapuyade 		return r;
37297f18414SEric Lapuyade 
37397f18414SEric Lapuyade 	activated = 0;
37497f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
37597f18414SEric Lapuyade 			      PN544_PL_NFCT_DEACTIVATED, &activated, 1);
37697f18414SEric Lapuyade 	if (r < 0)
37797f18414SEric Lapuyade 		return r;
37897f18414SEric Lapuyade 
37997f18414SEric Lapuyade 	if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
38097f18414SEric Lapuyade 			 NFC_PROTO_JEWEL_MASK))
38197f18414SEric Lapuyade 		phases |= 1;		/* Type A */
38297f18414SEric Lapuyade 	if (im_protocols & NFC_PROTO_FELICA_MASK) {
38397f18414SEric Lapuyade 		phases |= (1 << 2);	/* Type F 212 */
38497f18414SEric Lapuyade 		phases |= (1 << 3);	/* Type F 424 */
38597f18414SEric Lapuyade 	}
38697f18414SEric Lapuyade 
38797f18414SEric Lapuyade 	phases |= (1 << 5);		/* NFC active */
38897f18414SEric Lapuyade 
38997f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
39097f18414SEric Lapuyade 			      PN544_PL_RDPHASES, &phases, 1);
39197f18414SEric Lapuyade 	if (r < 0)
39297f18414SEric Lapuyade 		return r;
39397f18414SEric Lapuyade 
39497f18414SEric Lapuyade 	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
39597f18414SEric Lapuyade 		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
39697f18414SEric Lapuyade 							&hdev->gb_len);
39797f18414SEric Lapuyade 		pr_debug("generate local bytes %p", hdev->gb);
39897f18414SEric Lapuyade 		if (hdev->gb == NULL || hdev->gb_len == 0) {
39997f18414SEric Lapuyade 			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
40097f18414SEric Lapuyade 			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
40197f18414SEric Lapuyade 		}
40297f18414SEric Lapuyade 	}
40397f18414SEric Lapuyade 
40497f18414SEric Lapuyade 	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
40597f18414SEric Lapuyade 		r = nfc_hci_send_event(hdev,
40697f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
40797f18414SEric Lapuyade 				NFC_HCI_EVT_END_OPERATION, NULL, 0);
40897f18414SEric Lapuyade 		if (r < 0)
40997f18414SEric Lapuyade 			return r;
41097f18414SEric Lapuyade 
41197f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev,
41297f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41397f18414SEric Lapuyade 				PN544_DEP_MODE, &i_mode, 1);
41497f18414SEric Lapuyade 		if (r < 0)
41597f18414SEric Lapuyade 			return r;
41697f18414SEric Lapuyade 
41797f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev,
41897f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41997f18414SEric Lapuyade 				PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len);
42097f18414SEric Lapuyade 		if (r < 0)
42197f18414SEric Lapuyade 			return r;
42297f18414SEric Lapuyade 
42397f18414SEric Lapuyade 		r = nfc_hci_send_event(hdev,
42497f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
42597f18414SEric Lapuyade 				NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
42697f18414SEric Lapuyade 		if (r < 0)
42797f18414SEric Lapuyade 			nfc_hci_send_event(hdev,
42897f18414SEric Lapuyade 					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
42997f18414SEric Lapuyade 					NFC_HCI_EVT_END_OPERATION, NULL, 0);
43097f18414SEric Lapuyade 	}
43197f18414SEric Lapuyade 
43297f18414SEric Lapuyade 	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
43397f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
43497f18414SEric Lapuyade 				PN544_DEP_MODE, &t_mode, 1);
43597f18414SEric Lapuyade 		if (r < 0)
43697f18414SEric Lapuyade 			return r;
43797f18414SEric Lapuyade 
43897f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
43997f18414SEric Lapuyade 				PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len);
44097f18414SEric Lapuyade 		if (r < 0)
44197f18414SEric Lapuyade 			return r;
44297f18414SEric Lapuyade 
44397f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
44497f18414SEric Lapuyade 				PN544_DEP_MERGE, &t_merge, 1);
44597f18414SEric Lapuyade 		if (r < 0)
44697f18414SEric Lapuyade 			return r;
44797f18414SEric Lapuyade 	}
44897f18414SEric Lapuyade 
44997f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
45097f18414SEric Lapuyade 			       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
45197f18414SEric Lapuyade 	if (r < 0)
45297f18414SEric Lapuyade 		nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
45397f18414SEric Lapuyade 				   NFC_HCI_EVT_END_OPERATION, NULL, 0);
45497f18414SEric Lapuyade 
45597f18414SEric Lapuyade 	return r;
45697f18414SEric Lapuyade }
45797f18414SEric Lapuyade 
45897f18414SEric Lapuyade static int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev,
45997f18414SEric Lapuyade 				struct nfc_target *target, u8 comm_mode,
46097f18414SEric Lapuyade 				u8 *gb, size_t gb_len)
46197f18414SEric Lapuyade {
46297f18414SEric Lapuyade 	struct sk_buff *rgb_skb = NULL;
46397f18414SEric Lapuyade 	int r;
46497f18414SEric Lapuyade 
46597f18414SEric Lapuyade 	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
46697f18414SEric Lapuyade 				PN544_DEP_ATR_RES, &rgb_skb);
46797f18414SEric Lapuyade 	if (r < 0)
46897f18414SEric Lapuyade 		return r;
46997f18414SEric Lapuyade 
47097f18414SEric Lapuyade 	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
47197f18414SEric Lapuyade 		r = -EPROTO;
47297f18414SEric Lapuyade 		goto exit;
47397f18414SEric Lapuyade 	}
47497f18414SEric Lapuyade 	print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET,
47597f18414SEric Lapuyade 			16, 1, rgb_skb->data, rgb_skb->len, true);
47697f18414SEric Lapuyade 
47797f18414SEric Lapuyade 	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
47897f18414SEric Lapuyade 						rgb_skb->len);
47997f18414SEric Lapuyade 
48097f18414SEric Lapuyade 	if (r == 0)
48197f18414SEric Lapuyade 		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
48297f18414SEric Lapuyade 					NFC_RF_INITIATOR);
48397f18414SEric Lapuyade exit:
48497f18414SEric Lapuyade 	kfree_skb(rgb_skb);
48597f18414SEric Lapuyade 	return r;
48697f18414SEric Lapuyade }
48797f18414SEric Lapuyade 
48897f18414SEric Lapuyade static int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev)
48997f18414SEric Lapuyade {
49097f18414SEric Lapuyade 
49197f18414SEric Lapuyade 	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE,
49297f18414SEric Lapuyade 					NFC_HCI_EVT_END_OPERATION, NULL, 0);
49397f18414SEric Lapuyade }
49497f18414SEric Lapuyade 
49597f18414SEric Lapuyade static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
49697f18414SEric Lapuyade 				      struct nfc_target *target)
49797f18414SEric Lapuyade {
49897f18414SEric Lapuyade 	switch (gate) {
49997f18414SEric Lapuyade 	case PN544_RF_READER_F_GATE:
50097f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_FELICA_MASK;
50197f18414SEric Lapuyade 		break;
50297f18414SEric Lapuyade 	case PN544_RF_READER_JEWEL_GATE:
50397f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_JEWEL_MASK;
50497f18414SEric Lapuyade 		target->sens_res = 0x0c00;
50597f18414SEric Lapuyade 		break;
50697f18414SEric Lapuyade 	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
50797f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
50897f18414SEric Lapuyade 		break;
50997f18414SEric Lapuyade 	default:
51097f18414SEric Lapuyade 		return -EPROTO;
51197f18414SEric Lapuyade 	}
51297f18414SEric Lapuyade 
51397f18414SEric Lapuyade 	return 0;
51497f18414SEric Lapuyade }
51597f18414SEric Lapuyade 
51697f18414SEric Lapuyade static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
51797f18414SEric Lapuyade 						u8 gate,
51897f18414SEric Lapuyade 						struct nfc_target *target)
51997f18414SEric Lapuyade {
52097f18414SEric Lapuyade 	struct sk_buff *uid_skb;
52197f18414SEric Lapuyade 	int r = 0;
52297f18414SEric Lapuyade 
52397f18414SEric Lapuyade 	if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
52497f18414SEric Lapuyade 		return r;
52597f18414SEric Lapuyade 
52697f18414SEric Lapuyade 	if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
52797f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev,
52897f18414SEric Lapuyade 			PN544_RF_READER_NFCIP1_INITIATOR_GATE,
52997f18414SEric Lapuyade 			PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL);
53097f18414SEric Lapuyade 		if (r < 0)
53197f18414SEric Lapuyade 			return r;
53297f18414SEric Lapuyade 
53397f18414SEric Lapuyade 		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
53497f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
53597f18414SEric Lapuyade 		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
53697f18414SEric Lapuyade 		    target->nfcid1_len != 10)
53797f18414SEric Lapuyade 			return -EPROTO;
53897f18414SEric Lapuyade 
53997f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
54097f18414SEric Lapuyade 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
54197f18414SEric Lapuyade 				     target->nfcid1, target->nfcid1_len, NULL);
54297f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
54397f18414SEric Lapuyade 		r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE,
54497f18414SEric Lapuyade 				      PN544_FELICA_ID, &uid_skb);
54597f18414SEric Lapuyade 		if (r < 0)
54697f18414SEric Lapuyade 			return r;
54797f18414SEric Lapuyade 
54897f18414SEric Lapuyade 		if (uid_skb->len != 8) {
54997f18414SEric Lapuyade 			kfree_skb(uid_skb);
55097f18414SEric Lapuyade 			return -EPROTO;
55197f18414SEric Lapuyade 		}
55297f18414SEric Lapuyade 
55397f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
55497f18414SEric Lapuyade 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
55597f18414SEric Lapuyade 				     uid_skb->data, uid_skb->len, NULL);
55697f18414SEric Lapuyade 		kfree_skb(uid_skb);
55797f18414SEric Lapuyade 
55897f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev,
55997f18414SEric Lapuyade 					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
56097f18414SEric Lapuyade 					PN544_HCI_CMD_CONTINUE_ACTIVATION,
56197f18414SEric Lapuyade 					NULL, 0, NULL);
56297f18414SEric Lapuyade 		if (r < 0)
56397f18414SEric Lapuyade 			return r;
56497f18414SEric Lapuyade 
56597f18414SEric Lapuyade 		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
56697f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
56797f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
56897f18414SEric Lapuyade 		/*
56997f18414SEric Lapuyade 		 * TODO: maybe other ISO 14443 require some kind of continue
57097f18414SEric Lapuyade 		 * activation, but for now we've seen only this one below.
57197f18414SEric Lapuyade 		 */
57297f18414SEric Lapuyade 		if (target->sens_res == 0x4403)	/* Type 4 Mifare DESFire */
57397f18414SEric Lapuyade 			r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
57497f18414SEric Lapuyade 			      PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION,
57597f18414SEric Lapuyade 			      NULL, 0, NULL);
57697f18414SEric Lapuyade 	}
57797f18414SEric Lapuyade 
57897f18414SEric Lapuyade 	return r;
57997f18414SEric Lapuyade }
58097f18414SEric Lapuyade 
58197f18414SEric Lapuyade #define PN544_CB_TYPE_READER_F 1
58297f18414SEric Lapuyade 
58397f18414SEric Lapuyade static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
58497f18414SEric Lapuyade 				       int err)
58597f18414SEric Lapuyade {
58697f18414SEric Lapuyade 	struct pn544_hci_info *info = context;
58797f18414SEric Lapuyade 
58897f18414SEric Lapuyade 	switch (info->async_cb_type) {
58997f18414SEric Lapuyade 	case PN544_CB_TYPE_READER_F:
59097f18414SEric Lapuyade 		if (err == 0)
59197f18414SEric Lapuyade 			skb_pull(skb, 1);
59297f18414SEric Lapuyade 		info->async_cb(info->async_cb_context, skb, err);
59397f18414SEric Lapuyade 		break;
59497f18414SEric Lapuyade 	default:
59597f18414SEric Lapuyade 		if (err == 0)
59697f18414SEric Lapuyade 			kfree_skb(skb);
59797f18414SEric Lapuyade 		break;
59897f18414SEric Lapuyade 	}
59997f18414SEric Lapuyade }
60097f18414SEric Lapuyade 
60197f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_A	0x60
60297f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_B	0x61
60397f18414SEric Lapuyade #define MIFARE_CMD_HEADER	2
60497f18414SEric Lapuyade #define MIFARE_UID_LEN		4
60597f18414SEric Lapuyade #define MIFARE_KEY_LEN		6
60697f18414SEric Lapuyade #define MIFARE_CMD_LEN		12
60797f18414SEric Lapuyade /*
60897f18414SEric Lapuyade  * Returns:
60997f18414SEric Lapuyade  * <= 0: driver handled the data exchange
61097f18414SEric Lapuyade  *    1: driver doesn't especially handle, please do standard processing
61197f18414SEric Lapuyade  */
61297f18414SEric Lapuyade static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
61397f18414SEric Lapuyade 				   struct nfc_target *target,
61497f18414SEric Lapuyade 				   struct sk_buff *skb, data_exchange_cb_t cb,
61597f18414SEric Lapuyade 				   void *cb_context)
61697f18414SEric Lapuyade {
61797f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
61897f18414SEric Lapuyade 
61997f18414SEric Lapuyade 	pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
62097f18414SEric Lapuyade 		target->hci_reader_gate);
62197f18414SEric Lapuyade 
62297f18414SEric Lapuyade 	switch (target->hci_reader_gate) {
62397f18414SEric Lapuyade 	case NFC_HCI_RF_READER_A_GATE:
62497f18414SEric Lapuyade 		if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
62597f18414SEric Lapuyade 			/*
62697f18414SEric Lapuyade 			 * It seems that pn544 is inverting key and UID for
62797f18414SEric Lapuyade 			 * MIFARE authentication commands.
62897f18414SEric Lapuyade 			 */
62997f18414SEric Lapuyade 			if (skb->len == MIFARE_CMD_LEN &&
63097f18414SEric Lapuyade 			    (skb->data[0] == MIFARE_CMD_AUTH_KEY_A ||
63197f18414SEric Lapuyade 			     skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) {
63297f18414SEric Lapuyade 				u8 uid[MIFARE_UID_LEN];
63397f18414SEric Lapuyade 				u8 *data = skb->data + MIFARE_CMD_HEADER;
63497f18414SEric Lapuyade 
63597f18414SEric Lapuyade 				memcpy(uid, data + MIFARE_KEY_LEN,
63697f18414SEric Lapuyade 				       MIFARE_UID_LEN);
63797f18414SEric Lapuyade 				memmove(data + MIFARE_UID_LEN, data,
63897f18414SEric Lapuyade 					MIFARE_KEY_LEN);
63997f18414SEric Lapuyade 				memcpy(data, uid, MIFARE_UID_LEN);
64097f18414SEric Lapuyade 			}
64197f18414SEric Lapuyade 
64297f18414SEric Lapuyade 			return nfc_hci_send_cmd_async(hdev,
64397f18414SEric Lapuyade 						      target->hci_reader_gate,
64497f18414SEric Lapuyade 						      PN544_MIFARE_CMD,
64597f18414SEric Lapuyade 						      skb->data, skb->len,
64697f18414SEric Lapuyade 						      cb, cb_context);
64797f18414SEric Lapuyade 		} else
64897f18414SEric Lapuyade 			return 1;
64997f18414SEric Lapuyade 	case PN544_RF_READER_F_GATE:
65097f18414SEric Lapuyade 		*skb_push(skb, 1) = 0;
65197f18414SEric Lapuyade 		*skb_push(skb, 1) = 0;
65297f18414SEric Lapuyade 
65397f18414SEric Lapuyade 		info->async_cb_type = PN544_CB_TYPE_READER_F;
65497f18414SEric Lapuyade 		info->async_cb = cb;
65597f18414SEric Lapuyade 		info->async_cb_context = cb_context;
65697f18414SEric Lapuyade 
65797f18414SEric Lapuyade 		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
65897f18414SEric Lapuyade 					      PN544_FELICA_RAW, skb->data,
65997f18414SEric Lapuyade 					      skb->len,
66097f18414SEric Lapuyade 					      pn544_hci_data_exchange_cb, info);
66197f18414SEric Lapuyade 	case PN544_RF_READER_JEWEL_GATE:
66297f18414SEric Lapuyade 		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
66397f18414SEric Lapuyade 					      PN544_JEWEL_RAW_CMD, skb->data,
66497f18414SEric Lapuyade 					      skb->len, cb, cb_context);
66597f18414SEric Lapuyade 	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
66697f18414SEric Lapuyade 		*skb_push(skb, 1) = 0;
66797f18414SEric Lapuyade 
66897f18414SEric Lapuyade 		return nfc_hci_send_event(hdev, target->hci_reader_gate,
66997f18414SEric Lapuyade 					PN544_HCI_EVT_SND_DATA, skb->data,
67097f18414SEric Lapuyade 					skb->len);
67197f18414SEric Lapuyade 	default:
67297f18414SEric Lapuyade 		return 1;
67397f18414SEric Lapuyade 	}
67497f18414SEric Lapuyade }
67597f18414SEric Lapuyade 
67697f18414SEric Lapuyade static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
67797f18414SEric Lapuyade {
67897f18414SEric Lapuyade 	/* Set default false for multiple information chaining */
67997f18414SEric Lapuyade 	*skb_push(skb, 1) = 0;
68097f18414SEric Lapuyade 
68197f18414SEric Lapuyade 	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
68297f18414SEric Lapuyade 				PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
68397f18414SEric Lapuyade }
68497f18414SEric Lapuyade 
68597f18414SEric Lapuyade static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
68697f18414SEric Lapuyade 				   struct nfc_target *target)
68797f18414SEric Lapuyade {
68897f18414SEric Lapuyade 	pr_debug("supported protocol %d", target->supported_protocols);
68997f18414SEric Lapuyade 	if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
69097f18414SEric Lapuyade 					NFC_PROTO_ISO14443_B_MASK)) {
69197f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
69297f18414SEric Lapuyade 					PN544_RF_READER_CMD_PRESENCE_CHECK,
69397f18414SEric Lapuyade 					NULL, 0, NULL);
69497f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
69597f18414SEric Lapuyade 		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
69697f18414SEric Lapuyade 		    target->nfcid1_len != 10)
69797f18414SEric Lapuyade 			return -EOPNOTSUPP;
69897f18414SEric Lapuyade 
69997f18414SEric Lapuyade 		 return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
70097f18414SEric Lapuyade 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
70197f18414SEric Lapuyade 				     target->nfcid1, target->nfcid1_len, NULL);
70297f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_JEWEL_MASK) {
70397f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
70497f18414SEric Lapuyade 					PN544_JEWEL_RAW_CMD, NULL, 0, NULL);
70597f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
70697f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
70797f18414SEric Lapuyade 					PN544_FELICA_RAW, NULL, 0, NULL);
70897f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
70997f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
71097f18414SEric Lapuyade 					PN544_HCI_CMD_ATTREQUEST,
71197f18414SEric Lapuyade 					NULL, 0, NULL);
71297f18414SEric Lapuyade 	}
71397f18414SEric Lapuyade 
71497f18414SEric Lapuyade 	return 0;
71597f18414SEric Lapuyade }
71697f18414SEric Lapuyade 
717*27c31191SEric Lapuyade static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
718*27c31191SEric Lapuyade 				    struct sk_buff *skb)
71997f18414SEric Lapuyade {
72097f18414SEric Lapuyade 	struct sk_buff *rgb_skb = NULL;
72197f18414SEric Lapuyade 	int r = 0;
72297f18414SEric Lapuyade 
72397f18414SEric Lapuyade 	pr_debug("hci event %d", event);
72497f18414SEric Lapuyade 	switch (event) {
72597f18414SEric Lapuyade 	case PN544_HCI_EVT_ACTIVATED:
72697f18414SEric Lapuyade 		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
727*27c31191SEric Lapuyade 			r = nfc_hci_target_discovered(hdev, gate);
72897f18414SEric Lapuyade 		else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
72997f18414SEric Lapuyade 			r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
73097f18414SEric Lapuyade 					      &rgb_skb);
73197f18414SEric Lapuyade 			if (r < 0)
73297f18414SEric Lapuyade 				goto exit;
73397f18414SEric Lapuyade 
734*27c31191SEric Lapuyade 			r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
73597f18414SEric Lapuyade 					     NFC_COMM_PASSIVE, rgb_skb->data,
73697f18414SEric Lapuyade 					     rgb_skb->len);
73797f18414SEric Lapuyade 
73897f18414SEric Lapuyade 			kfree_skb(rgb_skb);
73997f18414SEric Lapuyade 		}
74097f18414SEric Lapuyade 		break;
74197f18414SEric Lapuyade 	case PN544_HCI_EVT_DEACTIVATED:
742*27c31191SEric Lapuyade 		r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
743*27c31191SEric Lapuyade 				       NULL, 0);
74497f18414SEric Lapuyade 		break;
74597f18414SEric Lapuyade 	case PN544_HCI_EVT_RCV_DATA:
74697f18414SEric Lapuyade 		if (skb->len < 2) {
74797f18414SEric Lapuyade 			r = -EPROTO;
74897f18414SEric Lapuyade 			goto exit;
74997f18414SEric Lapuyade 		}
75097f18414SEric Lapuyade 
75197f18414SEric Lapuyade 		if (skb->data[0] != 0) {
75297f18414SEric Lapuyade 			pr_debug("data0 %d", skb->data[0]);
75397f18414SEric Lapuyade 			r = -EPROTO;
75497f18414SEric Lapuyade 			goto exit;
75597f18414SEric Lapuyade 		}
75697f18414SEric Lapuyade 
75797f18414SEric Lapuyade 		skb_pull(skb, 2);
758*27c31191SEric Lapuyade 		return nfc_tm_data_received(hdev->ndev, skb);
75997f18414SEric Lapuyade 	default:
760*27c31191SEric Lapuyade 		pr_err("Discarded unknown event %x to gate %x\n", event, gate);
76197f18414SEric Lapuyade 		break;
76297f18414SEric Lapuyade 	}
76397f18414SEric Lapuyade 
76497f18414SEric Lapuyade exit:
76597f18414SEric Lapuyade 	kfree_skb(skb);
766*27c31191SEric Lapuyade 
767*27c31191SEric Lapuyade 	return r;
76897f18414SEric Lapuyade }
76997f18414SEric Lapuyade 
77097f18414SEric Lapuyade static struct nfc_hci_ops pn544_hci_ops = {
77197f18414SEric Lapuyade 	.open = pn544_hci_open,
77297f18414SEric Lapuyade 	.close = pn544_hci_close,
77397f18414SEric Lapuyade 	.hci_ready = pn544_hci_ready,
77497f18414SEric Lapuyade 	.xmit = pn544_hci_xmit,
77597f18414SEric Lapuyade 	.start_poll = pn544_hci_start_poll,
77697f18414SEric Lapuyade 	.dep_link_up = pn544_hci_dep_link_up,
77797f18414SEric Lapuyade 	.dep_link_down = pn544_hci_dep_link_down,
77897f18414SEric Lapuyade 	.target_from_gate = pn544_hci_target_from_gate,
77997f18414SEric Lapuyade 	.complete_target_discovered = pn544_hci_complete_target_discovered,
78097f18414SEric Lapuyade 	.im_transceive = pn544_hci_im_transceive,
78197f18414SEric Lapuyade 	.tm_send = pn544_hci_tm_send,
78297f18414SEric Lapuyade 	.check_presence = pn544_hci_check_presence,
78397f18414SEric Lapuyade 	.event_received = pn544_hci_event_received,
78497f18414SEric Lapuyade };
78597f18414SEric Lapuyade 
78697f18414SEric Lapuyade int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
78797f18414SEric Lapuyade 		    int phy_headroom, int phy_tailroom, int phy_payload,
78897f18414SEric Lapuyade 		    struct nfc_hci_dev **hdev)
78997f18414SEric Lapuyade {
79097f18414SEric Lapuyade 	struct pn544_hci_info *info;
79197f18414SEric Lapuyade 	u32 protocols;
79297f18414SEric Lapuyade 	struct nfc_hci_init_data init_data;
79397f18414SEric Lapuyade 	int r;
79497f18414SEric Lapuyade 
79597f18414SEric Lapuyade 	info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
79697f18414SEric Lapuyade 	if (!info) {
79797f18414SEric Lapuyade 		pr_err("Cannot allocate memory for pn544_hci_info.\n");
79897f18414SEric Lapuyade 		r = -ENOMEM;
79997f18414SEric Lapuyade 		goto err_info_alloc;
80097f18414SEric Lapuyade 	}
80197f18414SEric Lapuyade 
80297f18414SEric Lapuyade 	info->phy_ops = phy_ops;
80397f18414SEric Lapuyade 	info->phy_id = phy_id;
80497f18414SEric Lapuyade 	info->state = PN544_ST_COLD;
80597f18414SEric Lapuyade 	mutex_init(&info->info_lock);
80697f18414SEric Lapuyade 
80797f18414SEric Lapuyade 	init_data.gate_count = ARRAY_SIZE(pn544_gates);
80897f18414SEric Lapuyade 
80997f18414SEric Lapuyade 	memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates));
81097f18414SEric Lapuyade 
81197f18414SEric Lapuyade 	/*
81297f18414SEric Lapuyade 	 * TODO: Session id must include the driver name + some bus addr
81397f18414SEric Lapuyade 	 * persistent info to discriminate 2 identical chips
81497f18414SEric Lapuyade 	 */
81597f18414SEric Lapuyade 	strcpy(init_data.session_id, "ID544HCI");
81697f18414SEric Lapuyade 
81797f18414SEric Lapuyade 	protocols = NFC_PROTO_JEWEL_MASK |
81897f18414SEric Lapuyade 		    NFC_PROTO_MIFARE_MASK |
81997f18414SEric Lapuyade 		    NFC_PROTO_FELICA_MASK |
82097f18414SEric Lapuyade 		    NFC_PROTO_ISO14443_MASK |
82197f18414SEric Lapuyade 		    NFC_PROTO_ISO14443_B_MASK |
82297f18414SEric Lapuyade 		    NFC_PROTO_NFC_DEP_MASK;
82397f18414SEric Lapuyade 
82497f18414SEric Lapuyade 	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
82597f18414SEric Lapuyade 					     protocols, llc_name,
82697f18414SEric Lapuyade 					     phy_headroom + PN544_CMDS_HEADROOM,
82797f18414SEric Lapuyade 					     phy_tailroom, phy_payload);
82897f18414SEric Lapuyade 	if (!info->hdev) {
82997f18414SEric Lapuyade 		pr_err("Cannot allocate nfc hdev.\n");
83097f18414SEric Lapuyade 		r = -ENOMEM;
83197f18414SEric Lapuyade 		goto err_alloc_hdev;
83297f18414SEric Lapuyade 	}
83397f18414SEric Lapuyade 
83497f18414SEric Lapuyade 	nfc_hci_set_clientdata(info->hdev, info);
83597f18414SEric Lapuyade 
83697f18414SEric Lapuyade 	r = nfc_hci_register_device(info->hdev);
83797f18414SEric Lapuyade 	if (r)
83897f18414SEric Lapuyade 		goto err_regdev;
83997f18414SEric Lapuyade 
84097f18414SEric Lapuyade 	*hdev = info->hdev;
84197f18414SEric Lapuyade 
84297f18414SEric Lapuyade 	return 0;
84397f18414SEric Lapuyade 
84497f18414SEric Lapuyade err_regdev:
84597f18414SEric Lapuyade 	nfc_hci_free_device(info->hdev);
84697f18414SEric Lapuyade 
84797f18414SEric Lapuyade err_alloc_hdev:
84897f18414SEric Lapuyade 	kfree(info);
84997f18414SEric Lapuyade 
85097f18414SEric Lapuyade err_info_alloc:
85197f18414SEric Lapuyade 	return r;
85297f18414SEric Lapuyade }
85397f18414SEric Lapuyade 
85497f18414SEric Lapuyade void pn544_hci_remove(struct nfc_hci_dev *hdev)
85597f18414SEric Lapuyade {
85697f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
85797f18414SEric Lapuyade 
85897f18414SEric Lapuyade 	nfc_hci_unregister_device(hdev);
85997f18414SEric Lapuyade 	nfc_hci_free_device(hdev);
86097f18414SEric Lapuyade 	kfree(info);
86197f18414SEric Lapuyade }
862