xref: /linux/drivers/nfc/pn544/pn544.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
146fe7771SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
297f18414SEric Lapuyade /*
397f18414SEric Lapuyade  * HCI based Driver for NXP PN544 NFC Chip
497f18414SEric Lapuyade  *
597f18414SEric Lapuyade  * Copyright (C) 2012  Intel Corporation. All rights reserved.
697f18414SEric Lapuyade  */
797f18414SEric Lapuyade 
817936b43SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
917936b43SJoe Perches 
1097f18414SEric Lapuyade #include <linux/delay.h>
1197f18414SEric Lapuyade #include <linux/slab.h>
12aa741030SSamuel Ortiz #include <linux/module.h>
1397f18414SEric Lapuyade 
1497f18414SEric Lapuyade #include <linux/nfc.h>
1597f18414SEric Lapuyade #include <net/nfc/hci.h>
1697f18414SEric Lapuyade 
1797f18414SEric Lapuyade #include "pn544.h"
1897f18414SEric Lapuyade 
1997f18414SEric Lapuyade /* Timing restrictions (ms) */
2097f18414SEric Lapuyade #define PN544_HCI_RESETVEN_TIME		30
2197f18414SEric Lapuyade 
2297f18414SEric Lapuyade enum pn544_state {
2397f18414SEric Lapuyade 	PN544_ST_COLD,
2497f18414SEric Lapuyade 	PN544_ST_FW_READY,
2597f18414SEric Lapuyade 	PN544_ST_READY,
2697f18414SEric Lapuyade };
2797f18414SEric Lapuyade 
2897f18414SEric Lapuyade #define FULL_VERSION_LEN 11
2997f18414SEric Lapuyade 
3097f18414SEric Lapuyade /* Proprietary commands */
3197f18414SEric Lapuyade #define PN544_WRITE		0x3f
325faba2fdSArron Wang #define PN544_TEST_SWP		0x21
3397f18414SEric Lapuyade 
3497f18414SEric Lapuyade /* Proprietary gates, events, commands and registers */
3597f18414SEric Lapuyade 
3697f18414SEric Lapuyade /* NFC_HCI_RF_READER_A_GATE additional registers and commands */
3797f18414SEric Lapuyade #define PN544_RF_READER_A_AUTO_ACTIVATION			0x10
3897f18414SEric Lapuyade #define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION		0x12
3997f18414SEric Lapuyade #define PN544_MIFARE_CMD					0x21
4097f18414SEric Lapuyade 
4197f18414SEric Lapuyade /* Commands that apply to all RF readers */
4297f18414SEric Lapuyade #define PN544_RF_READER_CMD_PRESENCE_CHECK	0x30
4397f18414SEric Lapuyade #define PN544_RF_READER_CMD_ACTIVATE_NEXT	0x32
4497f18414SEric Lapuyade 
4597f18414SEric Lapuyade /* NFC_HCI_ID_MGMT_GATE additional registers */
4697f18414SEric Lapuyade #define PN544_ID_MGMT_FULL_VERSION_SW		0x10
4797f18414SEric Lapuyade 
4897f18414SEric Lapuyade #define PN544_RF_READER_ISO15693_GATE		0x12
4997f18414SEric Lapuyade 
5097f18414SEric Lapuyade #define PN544_RF_READER_F_GATE			0x14
5197f18414SEric Lapuyade #define PN544_FELICA_ID				0x04
5297f18414SEric Lapuyade #define PN544_FELICA_RAW			0x20
5397f18414SEric Lapuyade 
5497f18414SEric Lapuyade #define PN544_RF_READER_JEWEL_GATE		0x15
5597f18414SEric Lapuyade #define PN544_JEWEL_RAW_CMD			0x23
5697f18414SEric Lapuyade 
5797f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_INITIATOR_GATE	0x30
5897f18414SEric Lapuyade #define PN544_RF_READER_NFCIP1_TARGET_GATE	0x31
5997f18414SEric Lapuyade 
6097f18414SEric Lapuyade #define PN544_SYS_MGMT_GATE			0x90
6197f18414SEric Lapuyade #define PN544_SYS_MGMT_INFO_NOTIFICATION	0x02
6297f18414SEric Lapuyade 
6397f18414SEric Lapuyade #define PN544_POLLING_LOOP_MGMT_GATE		0x94
6497f18414SEric Lapuyade #define PN544_DEP_MODE				0x01
6597f18414SEric Lapuyade #define PN544_DEP_ATR_REQ			0x02
6697f18414SEric Lapuyade #define PN544_DEP_ATR_RES			0x03
6797f18414SEric Lapuyade #define PN544_DEP_MERGE				0x0D
6897f18414SEric Lapuyade #define PN544_PL_RDPHASES			0x06
6997f18414SEric Lapuyade #define PN544_PL_EMULATION			0x07
7097f18414SEric Lapuyade #define PN544_PL_NFCT_DEACTIVATED		0x09
7197f18414SEric Lapuyade 
7297f18414SEric Lapuyade #define PN544_SWP_MGMT_GATE			0xA0
7339438261SArron Wang #define PN544_SWP_DEFAULT_MODE			0x01
7497f18414SEric Lapuyade 
7597f18414SEric Lapuyade #define PN544_NFC_WI_MGMT_GATE			0xA1
765faba2fdSArron Wang #define PN544_NFC_ESE_DEFAULT_MODE		0x01
7797f18414SEric Lapuyade 
7897f18414SEric Lapuyade #define PN544_HCI_EVT_SND_DATA			0x01
7997f18414SEric Lapuyade #define PN544_HCI_EVT_ACTIVATED			0x02
8097f18414SEric Lapuyade #define PN544_HCI_EVT_DEACTIVATED		0x03
8197f18414SEric Lapuyade #define PN544_HCI_EVT_RCV_DATA			0x04
8297f18414SEric Lapuyade #define PN544_HCI_EVT_CONTINUE_MI		0x05
835faba2fdSArron Wang #define PN544_HCI_EVT_SWITCH_MODE		0x03
8497f18414SEric Lapuyade 
8597f18414SEric Lapuyade #define PN544_HCI_CMD_ATTREQUEST		0x12
8697f18414SEric Lapuyade #define PN544_HCI_CMD_CONTINUE_ACTIVATION	0x13
8797f18414SEric Lapuyade 
885f3e6393SKrzysztof Kozlowski static const struct nfc_hci_gate pn544_gates[] = {
8997f18414SEric Lapuyade 	{NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
9097f18414SEric Lapuyade 	{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
9197f18414SEric Lapuyade 	{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9297f18414SEric Lapuyade 	{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9397f18414SEric Lapuyade 	{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
9497f18414SEric Lapuyade 	{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
9597f18414SEric Lapuyade 	{PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9697f18414SEric Lapuyade 	{PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9797f18414SEric Lapuyade 	{PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9897f18414SEric Lapuyade 	{PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9997f18414SEric Lapuyade 	{PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
10097f18414SEric Lapuyade 	{PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE},
10197f18414SEric Lapuyade 	{PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
10297f18414SEric Lapuyade 	{PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE},
10397f18414SEric Lapuyade 	{PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE}
10497f18414SEric Lapuyade };
10597f18414SEric Lapuyade 
10697f18414SEric Lapuyade /* Largest headroom needed for outgoing custom commands */
10797f18414SEric Lapuyade #define PN544_CMDS_HEADROOM	2
10897f18414SEric Lapuyade 
10997f18414SEric Lapuyade struct pn544_hci_info {
1107a5e98daSKrzysztof Kozlowski 	const struct nfc_phy_ops *phy_ops;
11197f18414SEric Lapuyade 	void *phy_id;
11297f18414SEric Lapuyade 
11397f18414SEric Lapuyade 	struct nfc_hci_dev *hdev;
11497f18414SEric Lapuyade 
11597f18414SEric Lapuyade 	enum pn544_state state;
11697f18414SEric Lapuyade 
11797f18414SEric Lapuyade 	struct mutex info_lock;
11897f18414SEric Lapuyade 
11997f18414SEric Lapuyade 	int async_cb_type;
12097f18414SEric Lapuyade 	data_exchange_cb_t async_cb;
12197f18414SEric Lapuyade 	void *async_cb_context;
1228bd7fc89SEric Lapuyade 
1238bd7fc89SEric Lapuyade 	fw_download_t fw_download;
12497f18414SEric Lapuyade };
12597f18414SEric Lapuyade 
pn544_hci_open(struct nfc_hci_dev * hdev)12697f18414SEric Lapuyade static int pn544_hci_open(struct nfc_hci_dev *hdev)
12797f18414SEric Lapuyade {
12897f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
12997f18414SEric Lapuyade 	int r = 0;
13097f18414SEric Lapuyade 
13197f18414SEric Lapuyade 	mutex_lock(&info->info_lock);
13297f18414SEric Lapuyade 
13397f18414SEric Lapuyade 	if (info->state != PN544_ST_COLD) {
13497f18414SEric Lapuyade 		r = -EBUSY;
13597f18414SEric Lapuyade 		goto out;
13697f18414SEric Lapuyade 	}
13797f18414SEric Lapuyade 
13897f18414SEric Lapuyade 	r = info->phy_ops->enable(info->phy_id);
13997f18414SEric Lapuyade 
14097f18414SEric Lapuyade 	if (r == 0)
14197f18414SEric Lapuyade 		info->state = PN544_ST_READY;
14297f18414SEric Lapuyade 
14397f18414SEric Lapuyade out:
14497f18414SEric Lapuyade 	mutex_unlock(&info->info_lock);
14597f18414SEric Lapuyade 	return r;
14697f18414SEric Lapuyade }
14797f18414SEric Lapuyade 
pn544_hci_close(struct nfc_hci_dev * hdev)14897f18414SEric Lapuyade static void pn544_hci_close(struct nfc_hci_dev *hdev)
14997f18414SEric Lapuyade {
15097f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
15197f18414SEric Lapuyade 
15297f18414SEric Lapuyade 	mutex_lock(&info->info_lock);
15397f18414SEric Lapuyade 
15497f18414SEric Lapuyade 	if (info->state == PN544_ST_COLD)
15597f18414SEric Lapuyade 		goto out;
15697f18414SEric Lapuyade 
15797f18414SEric Lapuyade 	info->phy_ops->disable(info->phy_id);
15897f18414SEric Lapuyade 
15997f18414SEric Lapuyade 	info->state = PN544_ST_COLD;
16097f18414SEric Lapuyade 
16197f18414SEric Lapuyade out:
16297f18414SEric Lapuyade 	mutex_unlock(&info->info_lock);
16397f18414SEric Lapuyade }
16497f18414SEric Lapuyade 
pn544_hci_ready(struct nfc_hci_dev * hdev)16597f18414SEric Lapuyade static int pn544_hci_ready(struct nfc_hci_dev *hdev)
16697f18414SEric Lapuyade {
16797f18414SEric Lapuyade 	struct sk_buff *skb;
16897f18414SEric Lapuyade 	static struct hw_config {
16997f18414SEric Lapuyade 		u8 adr[2];
17097f18414SEric Lapuyade 		u8 value;
17197f18414SEric Lapuyade 	} hw_config[] = {
17297f18414SEric Lapuyade 		{{0x9f, 0x9a}, 0x00},
17397f18414SEric Lapuyade 
17497f18414SEric Lapuyade 		{{0x98, 0x10}, 0xbc},
17597f18414SEric Lapuyade 
17697f18414SEric Lapuyade 		{{0x9e, 0x71}, 0x00},
17797f18414SEric Lapuyade 
17897f18414SEric Lapuyade 		{{0x98, 0x09}, 0x00},
17997f18414SEric Lapuyade 
18097f18414SEric Lapuyade 		{{0x9e, 0xb4}, 0x00},
18197f18414SEric Lapuyade 
18297f18414SEric Lapuyade 		{{0x9c, 0x01}, 0x08},
18397f18414SEric Lapuyade 
18497f18414SEric Lapuyade 		{{0x9e, 0xaa}, 0x01},
18597f18414SEric Lapuyade 
18634f7e57bSArman Uguray 		{{0x9b, 0xd1}, 0x17},
18734f7e57bSArman Uguray 		{{0x9b, 0xd2}, 0x58},
18834f7e57bSArman Uguray 		{{0x9b, 0xd3}, 0x10},
18934f7e57bSArman Uguray 		{{0x9b, 0xd4}, 0x47},
19034f7e57bSArman Uguray 		{{0x9b, 0xd5}, 0x0c},
19134f7e57bSArman Uguray 		{{0x9b, 0xd6}, 0x37},
19234f7e57bSArman Uguray 		{{0x9b, 0xdd}, 0x33},
19397f18414SEric Lapuyade 
19434f7e57bSArman Uguray 		{{0x9b, 0x84}, 0x00},
19534f7e57bSArman Uguray 		{{0x99, 0x81}, 0x79},
19634f7e57bSArman Uguray 		{{0x99, 0x31}, 0x79},
19797f18414SEric Lapuyade 
19897f18414SEric Lapuyade 		{{0x98, 0x00}, 0x3f},
19997f18414SEric Lapuyade 
20034f7e57bSArman Uguray 		{{0x9f, 0x09}, 0x02},
20197f18414SEric Lapuyade 
20297f18414SEric Lapuyade 		{{0x9f, 0x0a}, 0x05},
20397f18414SEric Lapuyade 
20497f18414SEric Lapuyade 		{{0x9e, 0xd1}, 0xa1},
20534f7e57bSArman Uguray 		{{0x99, 0x23}, 0x01},
20697f18414SEric Lapuyade 
20734f7e57bSArman Uguray 		{{0x9e, 0x74}, 0x00},
20834f7e57bSArman Uguray 		{{0x9e, 0x90}, 0x00},
20997f18414SEric Lapuyade 		{{0x9f, 0x28}, 0x10},
21097f18414SEric Lapuyade 
21134f7e57bSArman Uguray 		{{0x9f, 0x35}, 0x04},
21297f18414SEric Lapuyade 
21334f7e57bSArman Uguray 		{{0x9f, 0x36}, 0x11},
21497f18414SEric Lapuyade 
21597f18414SEric Lapuyade 		{{0x9c, 0x31}, 0x00},
21697f18414SEric Lapuyade 
21734f7e57bSArman Uguray 		{{0x9c, 0x32}, 0x00},
21897f18414SEric Lapuyade 
21934f7e57bSArman Uguray 		{{0x9c, 0x19}, 0x0a},
22097f18414SEric Lapuyade 
22134f7e57bSArman Uguray 		{{0x9c, 0x1a}, 0x0a},
22297f18414SEric Lapuyade 
22397f18414SEric Lapuyade 		{{0x9c, 0x0c}, 0x00},
22497f18414SEric Lapuyade 
22597f18414SEric Lapuyade 		{{0x9c, 0x0d}, 0x00},
22697f18414SEric Lapuyade 
22797f18414SEric Lapuyade 		{{0x9c, 0x12}, 0x00},
22897f18414SEric Lapuyade 
22997f18414SEric Lapuyade 		{{0x9c, 0x13}, 0x00},
23097f18414SEric Lapuyade 
23134f7e57bSArman Uguray 		{{0x98, 0xa2}, 0x09},
23297f18414SEric Lapuyade 
23334f7e57bSArman Uguray 		{{0x98, 0x93}, 0x00},
23497f18414SEric Lapuyade 
23534f7e57bSArman Uguray 		{{0x98, 0x7d}, 0x08},
23697f18414SEric Lapuyade 		{{0x98, 0x7e}, 0x00},
23734f7e57bSArman Uguray 		{{0x9f, 0xc8}, 0x00},
23897f18414SEric Lapuyade 	};
23997f18414SEric Lapuyade 	struct hw_config *p = hw_config;
24097f18414SEric Lapuyade 	int count = ARRAY_SIZE(hw_config);
24197f18414SEric Lapuyade 	struct sk_buff *res_skb;
24297f18414SEric Lapuyade 	u8 param[4];
24397f18414SEric Lapuyade 	int r;
24497f18414SEric Lapuyade 
24597f18414SEric Lapuyade 	param[0] = 0;
24697f18414SEric Lapuyade 	while (count--) {
24797f18414SEric Lapuyade 		param[1] = p->adr[0];
24897f18414SEric Lapuyade 		param[2] = p->adr[1];
24997f18414SEric Lapuyade 		param[3] = p->value;
25097f18414SEric Lapuyade 
25197f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE,
25297f18414SEric Lapuyade 				     param, 4, &res_skb);
25397f18414SEric Lapuyade 		if (r < 0)
25497f18414SEric Lapuyade 			return r;
25597f18414SEric Lapuyade 
25697f18414SEric Lapuyade 		if (res_skb->len != 1) {
25797f18414SEric Lapuyade 			kfree_skb(res_skb);
25897f18414SEric Lapuyade 			return -EPROTO;
25997f18414SEric Lapuyade 		}
26097f18414SEric Lapuyade 
26197f18414SEric Lapuyade 		if (res_skb->data[0] != p->value) {
26297f18414SEric Lapuyade 			kfree_skb(res_skb);
26397f18414SEric Lapuyade 			return -EIO;
26497f18414SEric Lapuyade 		}
26597f18414SEric Lapuyade 
26697f18414SEric Lapuyade 		kfree_skb(res_skb);
26797f18414SEric Lapuyade 
26897f18414SEric Lapuyade 		p++;
26997f18414SEric Lapuyade 	}
27097f18414SEric Lapuyade 
27197f18414SEric Lapuyade 	param[0] = NFC_HCI_UICC_HOST_ID;
27297f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
27397f18414SEric Lapuyade 			      NFC_HCI_ADMIN_WHITELIST, param, 1);
27497f18414SEric Lapuyade 	if (r < 0)
27597f18414SEric Lapuyade 		return r;
27697f18414SEric Lapuyade 
27797f18414SEric Lapuyade 	param[0] = 0x3d;
27897f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE,
27997f18414SEric Lapuyade 			      PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1);
28097f18414SEric Lapuyade 	if (r < 0)
28197f18414SEric Lapuyade 		return r;
28297f18414SEric Lapuyade 
28397f18414SEric Lapuyade 	param[0] = 0x0;
28497f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE,
28597f18414SEric Lapuyade 			      PN544_RF_READER_A_AUTO_ACTIVATION, param, 1);
28697f18414SEric Lapuyade 	if (r < 0)
28797f18414SEric Lapuyade 		return r;
28897f18414SEric Lapuyade 
28997f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
29097f18414SEric Lapuyade 			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
29197f18414SEric Lapuyade 	if (r < 0)
29297f18414SEric Lapuyade 		return r;
29397f18414SEric Lapuyade 
29497f18414SEric Lapuyade 	param[0] = 0x1;
29597f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
29697f18414SEric Lapuyade 			      PN544_PL_NFCT_DEACTIVATED, param, 1);
29797f18414SEric Lapuyade 	if (r < 0)
29897f18414SEric Lapuyade 		return r;
29997f18414SEric Lapuyade 
30097f18414SEric Lapuyade 	param[0] = 0x0;
30197f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
30297f18414SEric Lapuyade 			      PN544_PL_RDPHASES, param, 1);
30397f18414SEric Lapuyade 	if (r < 0)
30497f18414SEric Lapuyade 		return r;
30597f18414SEric Lapuyade 
30697f18414SEric Lapuyade 	r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
30797f18414SEric Lapuyade 			      PN544_ID_MGMT_FULL_VERSION_SW, &skb);
30897f18414SEric Lapuyade 	if (r < 0)
30997f18414SEric Lapuyade 		return r;
31097f18414SEric Lapuyade 
31197f18414SEric Lapuyade 	if (skb->len != FULL_VERSION_LEN) {
31297f18414SEric Lapuyade 		kfree_skb(skb);
31397f18414SEric Lapuyade 		return -EINVAL;
31497f18414SEric Lapuyade 	}
31597f18414SEric Lapuyade 
31697f18414SEric Lapuyade 	print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
31797f18414SEric Lapuyade 		       DUMP_PREFIX_NONE, 16, 1,
31897f18414SEric Lapuyade 		       skb->data, FULL_VERSION_LEN, false);
31997f18414SEric Lapuyade 
32097f18414SEric Lapuyade 	kfree_skb(skb);
32197f18414SEric Lapuyade 
32297f18414SEric Lapuyade 	return 0;
32397f18414SEric Lapuyade }
32497f18414SEric Lapuyade 
pn544_hci_xmit(struct nfc_hci_dev * hdev,struct sk_buff * skb)32597f18414SEric Lapuyade static int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
32697f18414SEric Lapuyade {
32797f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
32897f18414SEric Lapuyade 
32997f18414SEric Lapuyade 	return info->phy_ops->write(info->phy_id, skb);
33097f18414SEric Lapuyade }
33197f18414SEric Lapuyade 
pn544_hci_start_poll(struct nfc_hci_dev * hdev,u32 im_protocols,u32 tm_protocols)33297f18414SEric Lapuyade static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
33397f18414SEric Lapuyade 				u32 im_protocols, u32 tm_protocols)
33497f18414SEric Lapuyade {
33597f18414SEric Lapuyade 	u8 phases = 0;
33697f18414SEric Lapuyade 	int r;
33797f18414SEric Lapuyade 	u8 duration[2];
33897f18414SEric Lapuyade 	u8 activated;
33997f18414SEric Lapuyade 	u8 i_mode = 0x3f; /* Enable all supported modes */
34097f18414SEric Lapuyade 	u8 t_mode = 0x0f;
34197f18414SEric Lapuyade 	u8 t_merge = 0x01; /* Enable merge by default */
34297f18414SEric Lapuyade 
34397f18414SEric Lapuyade 	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
34497f18414SEric Lapuyade 		__func__, im_protocols, tm_protocols);
34597f18414SEric Lapuyade 
34697f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
34797f18414SEric Lapuyade 			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
34897f18414SEric Lapuyade 	if (r < 0)
34997f18414SEric Lapuyade 		return r;
35097f18414SEric Lapuyade 
35197f18414SEric Lapuyade 	duration[0] = 0x18;
35297f18414SEric Lapuyade 	duration[1] = 0x6a;
35397f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
35497f18414SEric Lapuyade 			      PN544_PL_EMULATION, duration, 2);
35597f18414SEric Lapuyade 	if (r < 0)
35697f18414SEric Lapuyade 		return r;
35797f18414SEric Lapuyade 
35897f18414SEric Lapuyade 	activated = 0;
35997f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
36097f18414SEric Lapuyade 			      PN544_PL_NFCT_DEACTIVATED, &activated, 1);
36197f18414SEric Lapuyade 	if (r < 0)
36297f18414SEric Lapuyade 		return r;
36397f18414SEric Lapuyade 
36497f18414SEric Lapuyade 	if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
36597f18414SEric Lapuyade 			 NFC_PROTO_JEWEL_MASK))
36697f18414SEric Lapuyade 		phases |= 1;		/* Type A */
36797f18414SEric Lapuyade 	if (im_protocols & NFC_PROTO_FELICA_MASK) {
36897f18414SEric Lapuyade 		phases |= (1 << 2);	/* Type F 212 */
36997f18414SEric Lapuyade 		phases |= (1 << 3);	/* Type F 424 */
37097f18414SEric Lapuyade 	}
37197f18414SEric Lapuyade 
37297f18414SEric Lapuyade 	phases |= (1 << 5);		/* NFC active */
37397f18414SEric Lapuyade 
37497f18414SEric Lapuyade 	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
37597f18414SEric Lapuyade 			      PN544_PL_RDPHASES, &phases, 1);
37697f18414SEric Lapuyade 	if (r < 0)
37797f18414SEric Lapuyade 		return r;
37897f18414SEric Lapuyade 
37997f18414SEric Lapuyade 	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
38097f18414SEric Lapuyade 		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
38197f18414SEric Lapuyade 							&hdev->gb_len);
38217936b43SJoe Perches 		pr_debug("generate local bytes %p\n", hdev->gb);
38397f18414SEric Lapuyade 		if (hdev->gb == NULL || hdev->gb_len == 0) {
38497f18414SEric Lapuyade 			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38597f18414SEric Lapuyade 			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38697f18414SEric Lapuyade 		}
38797f18414SEric Lapuyade 	}
38897f18414SEric Lapuyade 
38997f18414SEric Lapuyade 	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
39097f18414SEric Lapuyade 		r = nfc_hci_send_event(hdev,
39197f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39297f18414SEric Lapuyade 				NFC_HCI_EVT_END_OPERATION, NULL, 0);
39397f18414SEric Lapuyade 		if (r < 0)
39497f18414SEric Lapuyade 			return r;
39597f18414SEric Lapuyade 
39697f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev,
39797f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39897f18414SEric Lapuyade 				PN544_DEP_MODE, &i_mode, 1);
39997f18414SEric Lapuyade 		if (r < 0)
40097f18414SEric Lapuyade 			return r;
40197f18414SEric Lapuyade 
40297f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev,
40397f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
40497f18414SEric Lapuyade 				PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len);
40597f18414SEric Lapuyade 		if (r < 0)
40697f18414SEric Lapuyade 			return r;
40797f18414SEric Lapuyade 
40897f18414SEric Lapuyade 		r = nfc_hci_send_event(hdev,
40997f18414SEric Lapuyade 				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41097f18414SEric Lapuyade 				NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
41197f18414SEric Lapuyade 		if (r < 0)
41297f18414SEric Lapuyade 			nfc_hci_send_event(hdev,
41397f18414SEric Lapuyade 					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41497f18414SEric Lapuyade 					NFC_HCI_EVT_END_OPERATION, NULL, 0);
41597f18414SEric Lapuyade 	}
41697f18414SEric Lapuyade 
41797f18414SEric Lapuyade 	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
41897f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
41997f18414SEric Lapuyade 				PN544_DEP_MODE, &t_mode, 1);
42097f18414SEric Lapuyade 		if (r < 0)
42197f18414SEric Lapuyade 			return r;
42297f18414SEric Lapuyade 
42397f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42497f18414SEric Lapuyade 				PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len);
42597f18414SEric Lapuyade 		if (r < 0)
42697f18414SEric Lapuyade 			return r;
42797f18414SEric Lapuyade 
42897f18414SEric Lapuyade 		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42997f18414SEric Lapuyade 				PN544_DEP_MERGE, &t_merge, 1);
43097f18414SEric Lapuyade 		if (r < 0)
43197f18414SEric Lapuyade 			return r;
43297f18414SEric Lapuyade 	}
43397f18414SEric Lapuyade 
43497f18414SEric Lapuyade 	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43597f18414SEric Lapuyade 			       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
43697f18414SEric Lapuyade 	if (r < 0)
43797f18414SEric Lapuyade 		nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43897f18414SEric Lapuyade 				   NFC_HCI_EVT_END_OPERATION, NULL, 0);
43997f18414SEric Lapuyade 
44097f18414SEric Lapuyade 	return r;
44197f18414SEric Lapuyade }
44297f18414SEric Lapuyade 
pn544_hci_dep_link_up(struct nfc_hci_dev * hdev,struct nfc_target * target,u8 comm_mode,u8 * gb,size_t gb_len)44397f18414SEric Lapuyade static int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev,
44497f18414SEric Lapuyade 				struct nfc_target *target, u8 comm_mode,
44597f18414SEric Lapuyade 				u8 *gb, size_t gb_len)
44697f18414SEric Lapuyade {
44797f18414SEric Lapuyade 	struct sk_buff *rgb_skb = NULL;
44897f18414SEric Lapuyade 	int r;
44997f18414SEric Lapuyade 
45097f18414SEric Lapuyade 	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
45197f18414SEric Lapuyade 				PN544_DEP_ATR_RES, &rgb_skb);
45297f18414SEric Lapuyade 	if (r < 0)
45397f18414SEric Lapuyade 		return r;
45497f18414SEric Lapuyade 
45597f18414SEric Lapuyade 	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
45697f18414SEric Lapuyade 		r = -EPROTO;
45797f18414SEric Lapuyade 		goto exit;
45897f18414SEric Lapuyade 	}
45997f18414SEric Lapuyade 	print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET,
46097f18414SEric Lapuyade 			16, 1, rgb_skb->data, rgb_skb->len, true);
46197f18414SEric Lapuyade 
46297f18414SEric Lapuyade 	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
46397f18414SEric Lapuyade 						rgb_skb->len);
46497f18414SEric Lapuyade 
46597f18414SEric Lapuyade 	if (r == 0)
46697f18414SEric Lapuyade 		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
46797f18414SEric Lapuyade 					NFC_RF_INITIATOR);
46897f18414SEric Lapuyade exit:
46997f18414SEric Lapuyade 	kfree_skb(rgb_skb);
47097f18414SEric Lapuyade 	return r;
47197f18414SEric Lapuyade }
47297f18414SEric Lapuyade 
pn544_hci_dep_link_down(struct nfc_hci_dev * hdev)47397f18414SEric Lapuyade static int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev)
47497f18414SEric Lapuyade {
47597f18414SEric Lapuyade 
47697f18414SEric Lapuyade 	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE,
47797f18414SEric Lapuyade 					NFC_HCI_EVT_END_OPERATION, NULL, 0);
47897f18414SEric Lapuyade }
47997f18414SEric Lapuyade 
pn544_hci_target_from_gate(struct nfc_hci_dev * hdev,u8 gate,struct nfc_target * target)48097f18414SEric Lapuyade static int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
48197f18414SEric Lapuyade 				      struct nfc_target *target)
48297f18414SEric Lapuyade {
48397f18414SEric Lapuyade 	switch (gate) {
48497f18414SEric Lapuyade 	case PN544_RF_READER_F_GATE:
48597f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_FELICA_MASK;
48697f18414SEric Lapuyade 		break;
48797f18414SEric Lapuyade 	case PN544_RF_READER_JEWEL_GATE:
48897f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_JEWEL_MASK;
48997f18414SEric Lapuyade 		target->sens_res = 0x0c00;
49097f18414SEric Lapuyade 		break;
49197f18414SEric Lapuyade 	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
49297f18414SEric Lapuyade 		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
49397f18414SEric Lapuyade 		break;
49497f18414SEric Lapuyade 	default:
49597f18414SEric Lapuyade 		return -EPROTO;
49697f18414SEric Lapuyade 	}
49797f18414SEric Lapuyade 
49897f18414SEric Lapuyade 	return 0;
49997f18414SEric Lapuyade }
50097f18414SEric Lapuyade 
pn544_hci_complete_target_discovered(struct nfc_hci_dev * hdev,u8 gate,struct nfc_target * target)50197f18414SEric Lapuyade static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
50297f18414SEric Lapuyade 						u8 gate,
50397f18414SEric Lapuyade 						struct nfc_target *target)
50497f18414SEric Lapuyade {
50597f18414SEric Lapuyade 	struct sk_buff *uid_skb;
50697f18414SEric Lapuyade 	int r = 0;
50797f18414SEric Lapuyade 
50897f18414SEric Lapuyade 	if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
50997f18414SEric Lapuyade 		return r;
51097f18414SEric Lapuyade 
51197f18414SEric Lapuyade 	if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
51297f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev,
51397f18414SEric Lapuyade 			PN544_RF_READER_NFCIP1_INITIATOR_GATE,
51497f18414SEric Lapuyade 			PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL);
51597f18414SEric Lapuyade 		if (r < 0)
51697f18414SEric Lapuyade 			return r;
51797f18414SEric Lapuyade 
51897f18414SEric Lapuyade 		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
51997f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
52097f18414SEric Lapuyade 		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
52197f18414SEric Lapuyade 		    target->nfcid1_len != 10)
52297f18414SEric Lapuyade 			return -EPROTO;
52397f18414SEric Lapuyade 
52497f18414SEric Lapuyade 		r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
52597f18414SEric Lapuyade 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
52697f18414SEric Lapuyade 				     target->nfcid1, target->nfcid1_len, NULL);
52797f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
52897f18414SEric Lapuyade 		r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE,
52997f18414SEric Lapuyade 				      PN544_FELICA_ID, &uid_skb);
53097f18414SEric Lapuyade 		if (r < 0)
53197f18414SEric Lapuyade 			return r;
53297f18414SEric Lapuyade 
53397f18414SEric Lapuyade 		if (uid_skb->len != 8) {
53497f18414SEric Lapuyade 			kfree_skb(uid_skb);
53597f18414SEric Lapuyade 			return -EPROTO;
53697f18414SEric Lapuyade 		}
53797f18414SEric Lapuyade 
5389c598440SArron Wang 		/* Type F NFC-DEP IDm has prefix 0x01FE */
5399c598440SArron Wang 		if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) {
54097f18414SEric Lapuyade 			kfree_skb(uid_skb);
54197f18414SEric Lapuyade 			r = nfc_hci_send_cmd(hdev,
54297f18414SEric Lapuyade 					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
54397f18414SEric Lapuyade 					PN544_HCI_CMD_CONTINUE_ACTIVATION,
54497f18414SEric Lapuyade 					NULL, 0, NULL);
54597f18414SEric Lapuyade 			if (r < 0)
54697f18414SEric Lapuyade 				return r;
54797f18414SEric Lapuyade 
54897f18414SEric Lapuyade 			target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
5499c598440SArron Wang 			target->hci_reader_gate =
5509c598440SArron Wang 				PN544_RF_READER_NFCIP1_INITIATOR_GATE;
5519c598440SArron Wang 		} else {
5529c598440SArron Wang 			r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
5539c598440SArron Wang 					     PN544_RF_READER_CMD_ACTIVATE_NEXT,
5549c598440SArron Wang 					     uid_skb->data, uid_skb->len, NULL);
5559c598440SArron Wang 			kfree_skb(uid_skb);
5569c598440SArron Wang 		}
55797f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
55897f18414SEric Lapuyade 		/*
55997f18414SEric Lapuyade 		 * TODO: maybe other ISO 14443 require some kind of continue
56097f18414SEric Lapuyade 		 * activation, but for now we've seen only this one below.
56197f18414SEric Lapuyade 		 */
56297f18414SEric Lapuyade 		if (target->sens_res == 0x4403)	/* Type 4 Mifare DESFire */
56397f18414SEric Lapuyade 			r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
56497f18414SEric Lapuyade 			      PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION,
56597f18414SEric Lapuyade 			      NULL, 0, NULL);
56697f18414SEric Lapuyade 	}
56797f18414SEric Lapuyade 
56897f18414SEric Lapuyade 	return r;
56997f18414SEric Lapuyade }
57097f18414SEric Lapuyade 
57197f18414SEric Lapuyade #define PN544_CB_TYPE_READER_F 1
57297f18414SEric Lapuyade 
pn544_hci_data_exchange_cb(void * context,struct sk_buff * skb,int err)57397f18414SEric Lapuyade static void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
57497f18414SEric Lapuyade 				       int err)
57597f18414SEric Lapuyade {
57697f18414SEric Lapuyade 	struct pn544_hci_info *info = context;
57797f18414SEric Lapuyade 
57897f18414SEric Lapuyade 	switch (info->async_cb_type) {
57997f18414SEric Lapuyade 	case PN544_CB_TYPE_READER_F:
58097f18414SEric Lapuyade 		if (err == 0)
58197f18414SEric Lapuyade 			skb_pull(skb, 1);
58297f18414SEric Lapuyade 		info->async_cb(info->async_cb_context, skb, err);
58397f18414SEric Lapuyade 		break;
58497f18414SEric Lapuyade 	default:
58597f18414SEric Lapuyade 		if (err == 0)
58697f18414SEric Lapuyade 			kfree_skb(skb);
58797f18414SEric Lapuyade 		break;
58897f18414SEric Lapuyade 	}
58997f18414SEric Lapuyade }
59097f18414SEric Lapuyade 
59197f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_A	0x60
59297f18414SEric Lapuyade #define MIFARE_CMD_AUTH_KEY_B	0x61
59397f18414SEric Lapuyade #define MIFARE_CMD_HEADER	2
59497f18414SEric Lapuyade #define MIFARE_UID_LEN		4
59597f18414SEric Lapuyade #define MIFARE_KEY_LEN		6
59697f18414SEric Lapuyade #define MIFARE_CMD_LEN		12
59797f18414SEric Lapuyade /*
59897f18414SEric Lapuyade  * Returns:
59997f18414SEric Lapuyade  * <= 0: driver handled the data exchange
60097f18414SEric Lapuyade  *    1: driver doesn't especially handle, please do standard processing
60197f18414SEric Lapuyade  */
pn544_hci_im_transceive(struct nfc_hci_dev * hdev,struct nfc_target * target,struct sk_buff * skb,data_exchange_cb_t cb,void * cb_context)60297f18414SEric Lapuyade static int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
60397f18414SEric Lapuyade 				   struct nfc_target *target,
60497f18414SEric Lapuyade 				   struct sk_buff *skb, data_exchange_cb_t cb,
60597f18414SEric Lapuyade 				   void *cb_context)
60697f18414SEric Lapuyade {
60797f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
60897f18414SEric Lapuyade 
60997f18414SEric Lapuyade 	pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
61097f18414SEric Lapuyade 		target->hci_reader_gate);
61197f18414SEric Lapuyade 
61297f18414SEric Lapuyade 	switch (target->hci_reader_gate) {
61397f18414SEric Lapuyade 	case NFC_HCI_RF_READER_A_GATE:
61497f18414SEric Lapuyade 		if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
61597f18414SEric Lapuyade 			/*
61697f18414SEric Lapuyade 			 * It seems that pn544 is inverting key and UID for
61797f18414SEric Lapuyade 			 * MIFARE authentication commands.
61897f18414SEric Lapuyade 			 */
61997f18414SEric Lapuyade 			if (skb->len == MIFARE_CMD_LEN &&
62097f18414SEric Lapuyade 			    (skb->data[0] == MIFARE_CMD_AUTH_KEY_A ||
62197f18414SEric Lapuyade 			     skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) {
62297f18414SEric Lapuyade 				u8 uid[MIFARE_UID_LEN];
62397f18414SEric Lapuyade 				u8 *data = skb->data + MIFARE_CMD_HEADER;
62497f18414SEric Lapuyade 
62597f18414SEric Lapuyade 				memcpy(uid, data + MIFARE_KEY_LEN,
62697f18414SEric Lapuyade 				       MIFARE_UID_LEN);
62797f18414SEric Lapuyade 				memmove(data + MIFARE_UID_LEN, data,
62897f18414SEric Lapuyade 					MIFARE_KEY_LEN);
62997f18414SEric Lapuyade 				memcpy(data, uid, MIFARE_UID_LEN);
63097f18414SEric Lapuyade 			}
63197f18414SEric Lapuyade 
63297f18414SEric Lapuyade 			return nfc_hci_send_cmd_async(hdev,
63397f18414SEric Lapuyade 						      target->hci_reader_gate,
63497f18414SEric Lapuyade 						      PN544_MIFARE_CMD,
63597f18414SEric Lapuyade 						      skb->data, skb->len,
63697f18414SEric Lapuyade 						      cb, cb_context);
63797f18414SEric Lapuyade 		} else
63897f18414SEric Lapuyade 			return 1;
63997f18414SEric Lapuyade 	case PN544_RF_READER_F_GATE:
640d58ff351SJohannes Berg 		*(u8 *)skb_push(skb, 1) = 0;
641d58ff351SJohannes Berg 		*(u8 *)skb_push(skb, 1) = 0;
64297f18414SEric Lapuyade 
64397f18414SEric Lapuyade 		info->async_cb_type = PN544_CB_TYPE_READER_F;
64497f18414SEric Lapuyade 		info->async_cb = cb;
64597f18414SEric Lapuyade 		info->async_cb_context = cb_context;
64697f18414SEric Lapuyade 
64797f18414SEric Lapuyade 		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
64897f18414SEric Lapuyade 					      PN544_FELICA_RAW, skb->data,
64997f18414SEric Lapuyade 					      skb->len,
65097f18414SEric Lapuyade 					      pn544_hci_data_exchange_cb, info);
65197f18414SEric Lapuyade 	case PN544_RF_READER_JEWEL_GATE:
65297f18414SEric Lapuyade 		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
65397f18414SEric Lapuyade 					      PN544_JEWEL_RAW_CMD, skb->data,
65497f18414SEric Lapuyade 					      skb->len, cb, cb_context);
65597f18414SEric Lapuyade 	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
656d58ff351SJohannes Berg 		*(u8 *)skb_push(skb, 1) = 0;
65797f18414SEric Lapuyade 
65897f18414SEric Lapuyade 		return nfc_hci_send_event(hdev, target->hci_reader_gate,
65997f18414SEric Lapuyade 					PN544_HCI_EVT_SND_DATA, skb->data,
66097f18414SEric Lapuyade 					skb->len);
66197f18414SEric Lapuyade 	default:
66297f18414SEric Lapuyade 		return 1;
66397f18414SEric Lapuyade 	}
66497f18414SEric Lapuyade }
66597f18414SEric Lapuyade 
pn544_hci_tm_send(struct nfc_hci_dev * hdev,struct sk_buff * skb)66697f18414SEric Lapuyade static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
66797f18414SEric Lapuyade {
668924d4a02SEric Lapuyade 	int r;
669924d4a02SEric Lapuyade 
67097f18414SEric Lapuyade 	/* Set default false for multiple information chaining */
671d58ff351SJohannes Berg 	*(u8 *)skb_push(skb, 1) = 0;
67297f18414SEric Lapuyade 
673924d4a02SEric Lapuyade 	r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
67497f18414SEric Lapuyade 			       PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
675924d4a02SEric Lapuyade 
676924d4a02SEric Lapuyade 	kfree_skb(skb);
677924d4a02SEric Lapuyade 
678924d4a02SEric Lapuyade 	return r;
67997f18414SEric Lapuyade }
68097f18414SEric Lapuyade 
pn544_hci_check_presence(struct nfc_hci_dev * hdev,struct nfc_target * target)68197f18414SEric Lapuyade static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
68297f18414SEric Lapuyade 				   struct nfc_target *target)
68397f18414SEric Lapuyade {
684c4c10784SChristophe JAILLET 	pr_debug("supported protocol %d\n", target->supported_protocols);
68597f18414SEric Lapuyade 	if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
68697f18414SEric Lapuyade 					NFC_PROTO_ISO14443_B_MASK)) {
68797f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
68897f18414SEric Lapuyade 					PN544_RF_READER_CMD_PRESENCE_CHECK,
68997f18414SEric Lapuyade 					NULL, 0, NULL);
69097f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
69197f18414SEric Lapuyade 		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
69297f18414SEric Lapuyade 		    target->nfcid1_len != 10)
69397f18414SEric Lapuyade 			return -EOPNOTSUPP;
69497f18414SEric Lapuyade 
69597f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
69697f18414SEric Lapuyade 				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
69797f18414SEric Lapuyade 				     target->nfcid1, target->nfcid1_len, NULL);
698a69bdc1eSArron Wang 	} else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
699a69bdc1eSArron Wang 						NFC_PROTO_FELICA_MASK)) {
700a69bdc1eSArron Wang 		return -EOPNOTSUPP;
70197f18414SEric Lapuyade 	} else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
70297f18414SEric Lapuyade 		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
70397f18414SEric Lapuyade 					PN544_HCI_CMD_ATTREQUEST,
70497f18414SEric Lapuyade 					NULL, 0, NULL);
70597f18414SEric Lapuyade 	}
70697f18414SEric Lapuyade 
70797f18414SEric Lapuyade 	return 0;
70897f18414SEric Lapuyade }
70997f18414SEric Lapuyade 
71040d06d36SEric Lapuyade /*
71140d06d36SEric Lapuyade  * Returns:
71240d06d36SEric Lapuyade  * <= 0: driver handled the event, skb consumed
71340d06d36SEric Lapuyade  *    1: driver does not handle the event, please do standard processing
71440d06d36SEric Lapuyade  */
pn544_hci_event_received(struct nfc_hci_dev * hdev,u8 pipe,u8 event,struct sk_buff * skb)7158abe3c6aSChristophe Ricard static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
71627c31191SEric Lapuyade 				    struct sk_buff *skb)
71797f18414SEric Lapuyade {
71897f18414SEric Lapuyade 	struct sk_buff *rgb_skb = NULL;
7198abe3c6aSChristophe Ricard 	u8 gate = hdev->pipes[pipe].gate;
72040d06d36SEric Lapuyade 	int r;
72197f18414SEric Lapuyade 
72217936b43SJoe Perches 	pr_debug("hci event %d\n", event);
72397f18414SEric Lapuyade 	switch (event) {
72497f18414SEric Lapuyade 	case PN544_HCI_EVT_ACTIVATED:
72540d06d36SEric Lapuyade 		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
72627c31191SEric Lapuyade 			r = nfc_hci_target_discovered(hdev, gate);
72740d06d36SEric Lapuyade 		} else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
72897f18414SEric Lapuyade 			r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
72997f18414SEric Lapuyade 					      &rgb_skb);
73097f18414SEric Lapuyade 			if (r < 0)
73197f18414SEric Lapuyade 				goto exit;
73297f18414SEric Lapuyade 
73327c31191SEric Lapuyade 			r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
73497f18414SEric Lapuyade 					     NFC_COMM_PASSIVE, rgb_skb->data,
73597f18414SEric Lapuyade 					     rgb_skb->len);
73697f18414SEric Lapuyade 
73797f18414SEric Lapuyade 			kfree_skb(rgb_skb);
73840d06d36SEric Lapuyade 		} else {
73940d06d36SEric Lapuyade 			r = -EINVAL;
74097f18414SEric Lapuyade 		}
74197f18414SEric Lapuyade 		break;
74297f18414SEric Lapuyade 	case PN544_HCI_EVT_DEACTIVATED:
74327c31191SEric Lapuyade 		r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
74427c31191SEric Lapuyade 				       NULL, 0);
74597f18414SEric Lapuyade 		break;
74697f18414SEric Lapuyade 	case PN544_HCI_EVT_RCV_DATA:
74797f18414SEric Lapuyade 		if (skb->len < 2) {
74897f18414SEric Lapuyade 			r = -EPROTO;
74997f18414SEric Lapuyade 			goto exit;
75097f18414SEric Lapuyade 		}
75197f18414SEric Lapuyade 
75297f18414SEric Lapuyade 		if (skb->data[0] != 0) {
75317936b43SJoe Perches 			pr_debug("data0 %d\n", skb->data[0]);
75497f18414SEric Lapuyade 			r = -EPROTO;
75597f18414SEric Lapuyade 			goto exit;
75697f18414SEric Lapuyade 		}
75797f18414SEric Lapuyade 
75897f18414SEric Lapuyade 		skb_pull(skb, 2);
75927c31191SEric Lapuyade 		return nfc_tm_data_received(hdev->ndev, skb);
76097f18414SEric Lapuyade 	default:
76140d06d36SEric Lapuyade 		return 1;
76297f18414SEric Lapuyade 	}
76397f18414SEric Lapuyade 
76497f18414SEric Lapuyade exit:
76597f18414SEric Lapuyade 	kfree_skb(skb);
76627c31191SEric Lapuyade 
76727c31191SEric Lapuyade 	return r;
76897f18414SEric Lapuyade }
76997f18414SEric Lapuyade 
pn544_hci_fw_download(struct nfc_hci_dev * hdev,const char * firmware_name)7708bd7fc89SEric Lapuyade static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
7718bd7fc89SEric Lapuyade 				 const char *firmware_name)
7728bd7fc89SEric Lapuyade {
7738bd7fc89SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
7748bd7fc89SEric Lapuyade 
7758bd7fc89SEric Lapuyade 	if (info->fw_download == NULL)
7768bd7fc89SEric Lapuyade 		return -ENOTSUPP;
7778bd7fc89SEric Lapuyade 
778971d63cfSArron Wang 	return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib);
7798bd7fc89SEric Lapuyade }
7808bd7fc89SEric Lapuyade 
pn544_hci_discover_se(struct nfc_hci_dev * hdev)7815faba2fdSArron Wang static int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
7825faba2fdSArron Wang {
7835faba2fdSArron Wang 	u32 se_idx = 0;
7845faba2fdSArron Wang 	u8 ese_mode = 0x01; /* Default mode */
7855faba2fdSArron Wang 	struct sk_buff *res_skb;
7865faba2fdSArron Wang 	int r;
7875faba2fdSArron Wang 
7885faba2fdSArron Wang 	r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP,
7895faba2fdSArron Wang 			     NULL, 0, &res_skb);
7905faba2fdSArron Wang 
7915faba2fdSArron Wang 	if (r == 0) {
7925faba2fdSArron Wang 		if (res_skb->len == 2 && res_skb->data[0] == 0x00)
7935faba2fdSArron Wang 			nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC);
7945faba2fdSArron Wang 
7955faba2fdSArron Wang 		kfree_skb(res_skb);
7965faba2fdSArron Wang 	}
7975faba2fdSArron Wang 
7985faba2fdSArron Wang 	r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE,
7995faba2fdSArron Wang 				PN544_HCI_EVT_SWITCH_MODE,
8005faba2fdSArron Wang 				&ese_mode, 1);
8015faba2fdSArron Wang 	if (r == 0)
8025faba2fdSArron Wang 		nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED);
8035faba2fdSArron Wang 
8045faba2fdSArron Wang 	return !se_idx;
8055faba2fdSArron Wang }
8065faba2fdSArron Wang 
80739438261SArron Wang #define PN544_SE_MODE_OFF	0x00
80839438261SArron Wang #define PN544_SE_MODE_ON	0x01
pn544_hci_enable_se(struct nfc_hci_dev * hdev,u32 se_idx)80939438261SArron Wang static int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
81039438261SArron Wang {
811*f2479c0aSKrzysztof Kozlowski 	const struct nfc_se *se;
81239438261SArron Wang 	u8 enable = PN544_SE_MODE_ON;
81339438261SArron Wang 	static struct uicc_gatelist {
81439438261SArron Wang 		u8 head;
81539438261SArron Wang 		u8 adr[2];
81639438261SArron Wang 		u8 value;
81739438261SArron Wang 	} uicc_gatelist[] = {
81839438261SArron Wang 		{0x00, {0x9e, 0xd9}, 0x23},
81939438261SArron Wang 		{0x00, {0x9e, 0xda}, 0x21},
82039438261SArron Wang 		{0x00, {0x9e, 0xdb}, 0x22},
82139438261SArron Wang 		{0x00, {0x9e, 0xdc}, 0x24},
82239438261SArron Wang 	};
82339438261SArron Wang 	struct uicc_gatelist *p = uicc_gatelist;
82439438261SArron Wang 	int count = ARRAY_SIZE(uicc_gatelist);
82539438261SArron Wang 	struct sk_buff *res_skb;
82639438261SArron Wang 	int r;
82739438261SArron Wang 
82839438261SArron Wang 	se = nfc_find_se(hdev->ndev, se_idx);
82939438261SArron Wang 
83039438261SArron Wang 	switch (se->type) {
83139438261SArron Wang 	case NFC_SE_UICC:
83239438261SArron Wang 		while (count--) {
83339438261SArron Wang 			r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE,
83439438261SArron Wang 					PN544_WRITE, (u8 *)p, 4, &res_skb);
83539438261SArron Wang 			if (r < 0)
83639438261SArron Wang 				return r;
83739438261SArron Wang 
83839438261SArron Wang 			if (res_skb->len != 1) {
83939438261SArron Wang 				kfree_skb(res_skb);
84039438261SArron Wang 				return -EPROTO;
84139438261SArron Wang 			}
84239438261SArron Wang 
84339438261SArron Wang 			if (res_skb->data[0] != p->value) {
84439438261SArron Wang 				kfree_skb(res_skb);
84539438261SArron Wang 				return -EIO;
84639438261SArron Wang 			}
84739438261SArron Wang 
84839438261SArron Wang 			kfree_skb(res_skb);
84939438261SArron Wang 
85039438261SArron Wang 			p++;
85139438261SArron Wang 		}
85239438261SArron Wang 
85339438261SArron Wang 		return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
85439438261SArron Wang 			      PN544_SWP_DEFAULT_MODE, &enable, 1);
85539438261SArron Wang 	case NFC_SE_EMBEDDED:
85639438261SArron Wang 		return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
85739438261SArron Wang 			      PN544_NFC_ESE_DEFAULT_MODE, &enable, 1);
85839438261SArron Wang 
85939438261SArron Wang 	default:
86039438261SArron Wang 		return -EINVAL;
86139438261SArron Wang 	}
86239438261SArron Wang }
86339438261SArron Wang 
pn544_hci_disable_se(struct nfc_hci_dev * hdev,u32 se_idx)86439438261SArron Wang static int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
86539438261SArron Wang {
866*f2479c0aSKrzysztof Kozlowski 	const struct nfc_se *se;
86739438261SArron Wang 	u8 disable = PN544_SE_MODE_OFF;
86839438261SArron Wang 
86939438261SArron Wang 	se = nfc_find_se(hdev->ndev, se_idx);
87039438261SArron Wang 
87139438261SArron Wang 	switch (se->type) {
87239438261SArron Wang 	case NFC_SE_UICC:
87339438261SArron Wang 		return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
87439438261SArron Wang 			      PN544_SWP_DEFAULT_MODE, &disable, 1);
87539438261SArron Wang 	case NFC_SE_EMBEDDED:
87639438261SArron Wang 		return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
87739438261SArron Wang 			      PN544_NFC_ESE_DEFAULT_MODE, &disable, 1);
87839438261SArron Wang 	default:
87939438261SArron Wang 		return -EINVAL;
88039438261SArron Wang 	}
88139438261SArron Wang }
88239438261SArron Wang 
883094c45c8SKrzysztof Kozlowski static const struct nfc_hci_ops pn544_hci_ops = {
88497f18414SEric Lapuyade 	.open = pn544_hci_open,
88597f18414SEric Lapuyade 	.close = pn544_hci_close,
88697f18414SEric Lapuyade 	.hci_ready = pn544_hci_ready,
88797f18414SEric Lapuyade 	.xmit = pn544_hci_xmit,
88897f18414SEric Lapuyade 	.start_poll = pn544_hci_start_poll,
88997f18414SEric Lapuyade 	.dep_link_up = pn544_hci_dep_link_up,
89097f18414SEric Lapuyade 	.dep_link_down = pn544_hci_dep_link_down,
89197f18414SEric Lapuyade 	.target_from_gate = pn544_hci_target_from_gate,
89297f18414SEric Lapuyade 	.complete_target_discovered = pn544_hci_complete_target_discovered,
89397f18414SEric Lapuyade 	.im_transceive = pn544_hci_im_transceive,
89497f18414SEric Lapuyade 	.tm_send = pn544_hci_tm_send,
89597f18414SEric Lapuyade 	.check_presence = pn544_hci_check_presence,
89697f18414SEric Lapuyade 	.event_received = pn544_hci_event_received,
8978bd7fc89SEric Lapuyade 	.fw_download = pn544_hci_fw_download,
8985faba2fdSArron Wang 	.discover_se = pn544_hci_discover_se,
89939438261SArron Wang 	.enable_se = pn544_hci_enable_se,
90039438261SArron Wang 	.disable_se = pn544_hci_disable_se,
90197f18414SEric Lapuyade };
90297f18414SEric Lapuyade 
pn544_hci_probe(void * phy_id,const struct nfc_phy_ops * phy_ops,char * llc_name,int phy_headroom,int phy_tailroom,int phy_payload,fw_download_t fw_download,struct nfc_hci_dev ** hdev)9037a5e98daSKrzysztof Kozlowski int pn544_hci_probe(void *phy_id, const struct nfc_phy_ops *phy_ops,
9047a5e98daSKrzysztof Kozlowski 		    char *llc_name, int phy_headroom, int phy_tailroom,
9057a5e98daSKrzysztof Kozlowski 		    int phy_payload, fw_download_t fw_download,
9067a5e98daSKrzysztof Kozlowski 		    struct nfc_hci_dev **hdev)
90797f18414SEric Lapuyade {
90897f18414SEric Lapuyade 	struct pn544_hci_info *info;
9090b456c41SSamuel Ortiz 	u32 protocols;
91097f18414SEric Lapuyade 	struct nfc_hci_init_data init_data;
91197f18414SEric Lapuyade 	int r;
91297f18414SEric Lapuyade 
91397f18414SEric Lapuyade 	info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
91497f18414SEric Lapuyade 	if (!info) {
91597f18414SEric Lapuyade 		r = -ENOMEM;
91697f18414SEric Lapuyade 		goto err_info_alloc;
91797f18414SEric Lapuyade 	}
91897f18414SEric Lapuyade 
91997f18414SEric Lapuyade 	info->phy_ops = phy_ops;
92097f18414SEric Lapuyade 	info->phy_id = phy_id;
9218bd7fc89SEric Lapuyade 	info->fw_download = fw_download;
92297f18414SEric Lapuyade 	info->state = PN544_ST_COLD;
92397f18414SEric Lapuyade 	mutex_init(&info->info_lock);
92497f18414SEric Lapuyade 
92597f18414SEric Lapuyade 	init_data.gate_count = ARRAY_SIZE(pn544_gates);
92697f18414SEric Lapuyade 
92797f18414SEric Lapuyade 	memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates));
92897f18414SEric Lapuyade 
92997f18414SEric Lapuyade 	/*
93097f18414SEric Lapuyade 	 * TODO: Session id must include the driver name + some bus addr
93197f18414SEric Lapuyade 	 * persistent info to discriminate 2 identical chips
93297f18414SEric Lapuyade 	 */
93397f18414SEric Lapuyade 	strcpy(init_data.session_id, "ID544HCI");
93497f18414SEric Lapuyade 
93597f18414SEric Lapuyade 	protocols = NFC_PROTO_JEWEL_MASK |
93697f18414SEric Lapuyade 		    NFC_PROTO_MIFARE_MASK |
93797f18414SEric Lapuyade 		    NFC_PROTO_FELICA_MASK |
93897f18414SEric Lapuyade 		    NFC_PROTO_ISO14443_MASK |
93997f18414SEric Lapuyade 		    NFC_PROTO_ISO14443_B_MASK |
94097f18414SEric Lapuyade 		    NFC_PROTO_NFC_DEP_MASK;
94197f18414SEric Lapuyade 
942bf71ab8bSEric Lapuyade 	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
9430b456c41SSamuel Ortiz 					     protocols, llc_name,
94497f18414SEric Lapuyade 					     phy_headroom + PN544_CMDS_HEADROOM,
94597f18414SEric Lapuyade 					     phy_tailroom, phy_payload);
94697f18414SEric Lapuyade 	if (!info->hdev) {
94717936b43SJoe Perches 		pr_err("Cannot allocate nfc hdev\n");
94897f18414SEric Lapuyade 		r = -ENOMEM;
94997f18414SEric Lapuyade 		goto err_alloc_hdev;
95097f18414SEric Lapuyade 	}
95197f18414SEric Lapuyade 
95297f18414SEric Lapuyade 	nfc_hci_set_clientdata(info->hdev, info);
95397f18414SEric Lapuyade 
95497f18414SEric Lapuyade 	r = nfc_hci_register_device(info->hdev);
95597f18414SEric Lapuyade 	if (r)
95697f18414SEric Lapuyade 		goto err_regdev;
95797f18414SEric Lapuyade 
95897f18414SEric Lapuyade 	*hdev = info->hdev;
95997f18414SEric Lapuyade 
96097f18414SEric Lapuyade 	return 0;
96197f18414SEric Lapuyade 
96297f18414SEric Lapuyade err_regdev:
96397f18414SEric Lapuyade 	nfc_hci_free_device(info->hdev);
96497f18414SEric Lapuyade 
96597f18414SEric Lapuyade err_alloc_hdev:
96697f18414SEric Lapuyade 	kfree(info);
96797f18414SEric Lapuyade 
96897f18414SEric Lapuyade err_info_alloc:
96997f18414SEric Lapuyade 	return r;
97097f18414SEric Lapuyade }
971aa741030SSamuel Ortiz EXPORT_SYMBOL(pn544_hci_probe);
97297f18414SEric Lapuyade 
pn544_hci_remove(struct nfc_hci_dev * hdev)97397f18414SEric Lapuyade void pn544_hci_remove(struct nfc_hci_dev *hdev)
97497f18414SEric Lapuyade {
97597f18414SEric Lapuyade 	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
97697f18414SEric Lapuyade 
97797f18414SEric Lapuyade 	nfc_hci_unregister_device(hdev);
97897f18414SEric Lapuyade 	nfc_hci_free_device(hdev);
97997f18414SEric Lapuyade 	kfree(info);
98097f18414SEric Lapuyade }
981aa741030SSamuel Ortiz EXPORT_SYMBOL(pn544_hci_remove);
982aa741030SSamuel Ortiz 
983aa741030SSamuel Ortiz MODULE_LICENSE("GPL");
984aa741030SSamuel Ortiz MODULE_DESCRIPTION(DRIVER_DESC);
985