162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * HCI based Driver for NXP PN544 NFC Chip
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012  Intel Corporation. All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/module.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/nfc.h>
1562306a36Sopenharmony_ci#include <net/nfc/hci.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "pn544.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/* Timing restrictions (ms) */
2062306a36Sopenharmony_ci#define PN544_HCI_RESETVEN_TIME		30
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cienum pn544_state {
2362306a36Sopenharmony_ci	PN544_ST_COLD,
2462306a36Sopenharmony_ci	PN544_ST_FW_READY,
2562306a36Sopenharmony_ci	PN544_ST_READY,
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#define FULL_VERSION_LEN 11
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci/* Proprietary commands */
3162306a36Sopenharmony_ci#define PN544_WRITE		0x3f
3262306a36Sopenharmony_ci#define PN544_TEST_SWP		0x21
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Proprietary gates, events, commands and registers */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* NFC_HCI_RF_READER_A_GATE additional registers and commands */
3762306a36Sopenharmony_ci#define PN544_RF_READER_A_AUTO_ACTIVATION			0x10
3862306a36Sopenharmony_ci#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION		0x12
3962306a36Sopenharmony_ci#define PN544_MIFARE_CMD					0x21
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci/* Commands that apply to all RF readers */
4262306a36Sopenharmony_ci#define PN544_RF_READER_CMD_PRESENCE_CHECK	0x30
4362306a36Sopenharmony_ci#define PN544_RF_READER_CMD_ACTIVATE_NEXT	0x32
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/* NFC_HCI_ID_MGMT_GATE additional registers */
4662306a36Sopenharmony_ci#define PN544_ID_MGMT_FULL_VERSION_SW		0x10
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define PN544_RF_READER_ISO15693_GATE		0x12
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define PN544_RF_READER_F_GATE			0x14
5162306a36Sopenharmony_ci#define PN544_FELICA_ID				0x04
5262306a36Sopenharmony_ci#define PN544_FELICA_RAW			0x20
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define PN544_RF_READER_JEWEL_GATE		0x15
5562306a36Sopenharmony_ci#define PN544_JEWEL_RAW_CMD			0x23
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define PN544_RF_READER_NFCIP1_INITIATOR_GATE	0x30
5862306a36Sopenharmony_ci#define PN544_RF_READER_NFCIP1_TARGET_GATE	0x31
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define PN544_SYS_MGMT_GATE			0x90
6162306a36Sopenharmony_ci#define PN544_SYS_MGMT_INFO_NOTIFICATION	0x02
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci#define PN544_POLLING_LOOP_MGMT_GATE		0x94
6462306a36Sopenharmony_ci#define PN544_DEP_MODE				0x01
6562306a36Sopenharmony_ci#define PN544_DEP_ATR_REQ			0x02
6662306a36Sopenharmony_ci#define PN544_DEP_ATR_RES			0x03
6762306a36Sopenharmony_ci#define PN544_DEP_MERGE				0x0D
6862306a36Sopenharmony_ci#define PN544_PL_RDPHASES			0x06
6962306a36Sopenharmony_ci#define PN544_PL_EMULATION			0x07
7062306a36Sopenharmony_ci#define PN544_PL_NFCT_DEACTIVATED		0x09
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define PN544_SWP_MGMT_GATE			0xA0
7362306a36Sopenharmony_ci#define PN544_SWP_DEFAULT_MODE			0x01
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define PN544_NFC_WI_MGMT_GATE			0xA1
7662306a36Sopenharmony_ci#define PN544_NFC_ESE_DEFAULT_MODE		0x01
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci#define PN544_HCI_EVT_SND_DATA			0x01
7962306a36Sopenharmony_ci#define PN544_HCI_EVT_ACTIVATED			0x02
8062306a36Sopenharmony_ci#define PN544_HCI_EVT_DEACTIVATED		0x03
8162306a36Sopenharmony_ci#define PN544_HCI_EVT_RCV_DATA			0x04
8262306a36Sopenharmony_ci#define PN544_HCI_EVT_CONTINUE_MI		0x05
8362306a36Sopenharmony_ci#define PN544_HCI_EVT_SWITCH_MODE		0x03
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#define PN544_HCI_CMD_ATTREQUEST		0x12
8662306a36Sopenharmony_ci#define PN544_HCI_CMD_CONTINUE_ACTIVATION	0x13
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic const struct nfc_hci_gate pn544_gates[] = {
8962306a36Sopenharmony_ci	{NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE},
9062306a36Sopenharmony_ci	{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
9162306a36Sopenharmony_ci	{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9262306a36Sopenharmony_ci	{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9362306a36Sopenharmony_ci	{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
9462306a36Sopenharmony_ci	{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
9562306a36Sopenharmony_ci	{PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9662306a36Sopenharmony_ci	{PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9762306a36Sopenharmony_ci	{PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9862306a36Sopenharmony_ci	{PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE},
9962306a36Sopenharmony_ci	{PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
10062306a36Sopenharmony_ci	{PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE},
10162306a36Sopenharmony_ci	{PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
10262306a36Sopenharmony_ci	{PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE},
10362306a36Sopenharmony_ci	{PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE}
10462306a36Sopenharmony_ci};
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/* Largest headroom needed for outgoing custom commands */
10762306a36Sopenharmony_ci#define PN544_CMDS_HEADROOM	2
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistruct pn544_hci_info {
11062306a36Sopenharmony_ci	const struct nfc_phy_ops *phy_ops;
11162306a36Sopenharmony_ci	void *phy_id;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	struct nfc_hci_dev *hdev;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	enum pn544_state state;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	struct mutex info_lock;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	int async_cb_type;
12062306a36Sopenharmony_ci	data_exchange_cb_t async_cb;
12162306a36Sopenharmony_ci	void *async_cb_context;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	fw_download_t fw_download;
12462306a36Sopenharmony_ci};
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_cistatic int pn544_hci_open(struct nfc_hci_dev *hdev)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
12962306a36Sopenharmony_ci	int r = 0;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	mutex_lock(&info->info_lock);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (info->state != PN544_ST_COLD) {
13462306a36Sopenharmony_ci		r = -EBUSY;
13562306a36Sopenharmony_ci		goto out;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	r = info->phy_ops->enable(info->phy_id);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (r == 0)
14162306a36Sopenharmony_ci		info->state = PN544_ST_READY;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ciout:
14462306a36Sopenharmony_ci	mutex_unlock(&info->info_lock);
14562306a36Sopenharmony_ci	return r;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void pn544_hci_close(struct nfc_hci_dev *hdev)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	mutex_lock(&info->info_lock);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (info->state == PN544_ST_COLD)
15562306a36Sopenharmony_ci		goto out;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	info->phy_ops->disable(info->phy_id);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	info->state = PN544_ST_COLD;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ciout:
16262306a36Sopenharmony_ci	mutex_unlock(&info->info_lock);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int pn544_hci_ready(struct nfc_hci_dev *hdev)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct sk_buff *skb;
16862306a36Sopenharmony_ci	static struct hw_config {
16962306a36Sopenharmony_ci		u8 adr[2];
17062306a36Sopenharmony_ci		u8 value;
17162306a36Sopenharmony_ci	} hw_config[] = {
17262306a36Sopenharmony_ci		{{0x9f, 0x9a}, 0x00},
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci		{{0x98, 0x10}, 0xbc},
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci		{{0x9e, 0x71}, 0x00},
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci		{{0x98, 0x09}, 0x00},
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci		{{0x9e, 0xb4}, 0x00},
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci		{{0x9c, 0x01}, 0x08},
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci		{{0x9e, 0xaa}, 0x01},
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci		{{0x9b, 0xd1}, 0x17},
18762306a36Sopenharmony_ci		{{0x9b, 0xd2}, 0x58},
18862306a36Sopenharmony_ci		{{0x9b, 0xd3}, 0x10},
18962306a36Sopenharmony_ci		{{0x9b, 0xd4}, 0x47},
19062306a36Sopenharmony_ci		{{0x9b, 0xd5}, 0x0c},
19162306a36Sopenharmony_ci		{{0x9b, 0xd6}, 0x37},
19262306a36Sopenharmony_ci		{{0x9b, 0xdd}, 0x33},
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci		{{0x9b, 0x84}, 0x00},
19562306a36Sopenharmony_ci		{{0x99, 0x81}, 0x79},
19662306a36Sopenharmony_ci		{{0x99, 0x31}, 0x79},
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci		{{0x98, 0x00}, 0x3f},
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci		{{0x9f, 0x09}, 0x02},
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci		{{0x9f, 0x0a}, 0x05},
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		{{0x9e, 0xd1}, 0xa1},
20562306a36Sopenharmony_ci		{{0x99, 0x23}, 0x01},
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci		{{0x9e, 0x74}, 0x00},
20862306a36Sopenharmony_ci		{{0x9e, 0x90}, 0x00},
20962306a36Sopenharmony_ci		{{0x9f, 0x28}, 0x10},
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci		{{0x9f, 0x35}, 0x04},
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci		{{0x9f, 0x36}, 0x11},
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		{{0x9c, 0x31}, 0x00},
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		{{0x9c, 0x32}, 0x00},
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci		{{0x9c, 0x19}, 0x0a},
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci		{{0x9c, 0x1a}, 0x0a},
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci		{{0x9c, 0x0c}, 0x00},
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		{{0x9c, 0x0d}, 0x00},
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci		{{0x9c, 0x12}, 0x00},
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		{{0x9c, 0x13}, 0x00},
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		{{0x98, 0xa2}, 0x09},
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		{{0x98, 0x93}, 0x00},
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		{{0x98, 0x7d}, 0x08},
23662306a36Sopenharmony_ci		{{0x98, 0x7e}, 0x00},
23762306a36Sopenharmony_ci		{{0x9f, 0xc8}, 0x00},
23862306a36Sopenharmony_ci	};
23962306a36Sopenharmony_ci	struct hw_config *p = hw_config;
24062306a36Sopenharmony_ci	int count = ARRAY_SIZE(hw_config);
24162306a36Sopenharmony_ci	struct sk_buff *res_skb;
24262306a36Sopenharmony_ci	u8 param[4];
24362306a36Sopenharmony_ci	int r;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	param[0] = 0;
24662306a36Sopenharmony_ci	while (count--) {
24762306a36Sopenharmony_ci		param[1] = p->adr[0];
24862306a36Sopenharmony_ci		param[2] = p->adr[1];
24962306a36Sopenharmony_ci		param[3] = p->value;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE,
25262306a36Sopenharmony_ci				     param, 4, &res_skb);
25362306a36Sopenharmony_ci		if (r < 0)
25462306a36Sopenharmony_ci			return r;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		if (res_skb->len != 1) {
25762306a36Sopenharmony_ci			kfree_skb(res_skb);
25862306a36Sopenharmony_ci			return -EPROTO;
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci		if (res_skb->data[0] != p->value) {
26262306a36Sopenharmony_ci			kfree_skb(res_skb);
26362306a36Sopenharmony_ci			return -EIO;
26462306a36Sopenharmony_ci		}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		kfree_skb(res_skb);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		p++;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	param[0] = NFC_HCI_UICC_HOST_ID;
27262306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
27362306a36Sopenharmony_ci			      NFC_HCI_ADMIN_WHITELIST, param, 1);
27462306a36Sopenharmony_ci	if (r < 0)
27562306a36Sopenharmony_ci		return r;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	param[0] = 0x3d;
27862306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE,
27962306a36Sopenharmony_ci			      PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1);
28062306a36Sopenharmony_ci	if (r < 0)
28162306a36Sopenharmony_ci		return r;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	param[0] = 0x0;
28462306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE,
28562306a36Sopenharmony_ci			      PN544_RF_READER_A_AUTO_ACTIVATION, param, 1);
28662306a36Sopenharmony_ci	if (r < 0)
28762306a36Sopenharmony_ci		return r;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
29062306a36Sopenharmony_ci			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
29162306a36Sopenharmony_ci	if (r < 0)
29262306a36Sopenharmony_ci		return r;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	param[0] = 0x1;
29562306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
29662306a36Sopenharmony_ci			      PN544_PL_NFCT_DEACTIVATED, param, 1);
29762306a36Sopenharmony_ci	if (r < 0)
29862306a36Sopenharmony_ci		return r;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	param[0] = 0x0;
30162306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
30262306a36Sopenharmony_ci			      PN544_PL_RDPHASES, param, 1);
30362306a36Sopenharmony_ci	if (r < 0)
30462306a36Sopenharmony_ci		return r;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
30762306a36Sopenharmony_ci			      PN544_ID_MGMT_FULL_VERSION_SW, &skb);
30862306a36Sopenharmony_ci	if (r < 0)
30962306a36Sopenharmony_ci		return r;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (skb->len != FULL_VERSION_LEN) {
31262306a36Sopenharmony_ci		kfree_skb(skb);
31362306a36Sopenharmony_ci		return -EINVAL;
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
31762306a36Sopenharmony_ci		       DUMP_PREFIX_NONE, 16, 1,
31862306a36Sopenharmony_ci		       skb->data, FULL_VERSION_LEN, false);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	kfree_skb(skb);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic int pn544_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	return info->phy_ops->write(info->phy_id, skb);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_cistatic int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
33362306a36Sopenharmony_ci				u32 im_protocols, u32 tm_protocols)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	u8 phases = 0;
33662306a36Sopenharmony_ci	int r;
33762306a36Sopenharmony_ci	u8 duration[2];
33862306a36Sopenharmony_ci	u8 activated;
33962306a36Sopenharmony_ci	u8 i_mode = 0x3f; /* Enable all supported modes */
34062306a36Sopenharmony_ci	u8 t_mode = 0x0f;
34162306a36Sopenharmony_ci	u8 t_merge = 0x01; /* Enable merge by default */
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
34462306a36Sopenharmony_ci		__func__, im_protocols, tm_protocols);
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
34762306a36Sopenharmony_ci			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
34862306a36Sopenharmony_ci	if (r < 0)
34962306a36Sopenharmony_ci		return r;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	duration[0] = 0x18;
35262306a36Sopenharmony_ci	duration[1] = 0x6a;
35362306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
35462306a36Sopenharmony_ci			      PN544_PL_EMULATION, duration, 2);
35562306a36Sopenharmony_ci	if (r < 0)
35662306a36Sopenharmony_ci		return r;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	activated = 0;
35962306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
36062306a36Sopenharmony_ci			      PN544_PL_NFCT_DEACTIVATED, &activated, 1);
36162306a36Sopenharmony_ci	if (r < 0)
36262306a36Sopenharmony_ci		return r;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	if (im_protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK |
36562306a36Sopenharmony_ci			 NFC_PROTO_JEWEL_MASK))
36662306a36Sopenharmony_ci		phases |= 1;		/* Type A */
36762306a36Sopenharmony_ci	if (im_protocols & NFC_PROTO_FELICA_MASK) {
36862306a36Sopenharmony_ci		phases |= (1 << 2);	/* Type F 212 */
36962306a36Sopenharmony_ci		phases |= (1 << 3);	/* Type F 424 */
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	phases |= (1 << 5);		/* NFC active */
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE,
37562306a36Sopenharmony_ci			      PN544_PL_RDPHASES, &phases, 1);
37662306a36Sopenharmony_ci	if (r < 0)
37762306a36Sopenharmony_ci		return r;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
38062306a36Sopenharmony_ci		hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
38162306a36Sopenharmony_ci							&hdev->gb_len);
38262306a36Sopenharmony_ci		pr_debug("generate local bytes %p\n", hdev->gb);
38362306a36Sopenharmony_ci		if (hdev->gb == NULL || hdev->gb_len == 0) {
38462306a36Sopenharmony_ci			im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38562306a36Sopenharmony_ci			tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	if (im_protocols & NFC_PROTO_NFC_DEP_MASK) {
39062306a36Sopenharmony_ci		r = nfc_hci_send_event(hdev,
39162306a36Sopenharmony_ci				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39262306a36Sopenharmony_ci				NFC_HCI_EVT_END_OPERATION, NULL, 0);
39362306a36Sopenharmony_ci		if (r < 0)
39462306a36Sopenharmony_ci			return r;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		r = nfc_hci_set_param(hdev,
39762306a36Sopenharmony_ci				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
39862306a36Sopenharmony_ci				PN544_DEP_MODE, &i_mode, 1);
39962306a36Sopenharmony_ci		if (r < 0)
40062306a36Sopenharmony_ci			return r;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		r = nfc_hci_set_param(hdev,
40362306a36Sopenharmony_ci				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
40462306a36Sopenharmony_ci				PN544_DEP_ATR_REQ, hdev->gb, hdev->gb_len);
40562306a36Sopenharmony_ci		if (r < 0)
40662306a36Sopenharmony_ci			return r;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci		r = nfc_hci_send_event(hdev,
40962306a36Sopenharmony_ci				PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41062306a36Sopenharmony_ci				NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
41162306a36Sopenharmony_ci		if (r < 0)
41262306a36Sopenharmony_ci			nfc_hci_send_event(hdev,
41362306a36Sopenharmony_ci					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
41462306a36Sopenharmony_ci					NFC_HCI_EVT_END_OPERATION, NULL, 0);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
41862306a36Sopenharmony_ci		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
41962306a36Sopenharmony_ci				PN544_DEP_MODE, &t_mode, 1);
42062306a36Sopenharmony_ci		if (r < 0)
42162306a36Sopenharmony_ci			return r;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42462306a36Sopenharmony_ci				PN544_DEP_ATR_RES, hdev->gb, hdev->gb_len);
42562306a36Sopenharmony_ci		if (r < 0)
42662306a36Sopenharmony_ci			return r;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		r = nfc_hci_set_param(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
42962306a36Sopenharmony_ci				PN544_DEP_MERGE, &t_merge, 1);
43062306a36Sopenharmony_ci		if (r < 0)
43162306a36Sopenharmony_ci			return r;
43262306a36Sopenharmony_ci	}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43562306a36Sopenharmony_ci			       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
43662306a36Sopenharmony_ci	if (r < 0)
43762306a36Sopenharmony_ci		nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
43862306a36Sopenharmony_ci				   NFC_HCI_EVT_END_OPERATION, NULL, 0);
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	return r;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int pn544_hci_dep_link_up(struct nfc_hci_dev *hdev,
44462306a36Sopenharmony_ci				struct nfc_target *target, u8 comm_mode,
44562306a36Sopenharmony_ci				u8 *gb, size_t gb_len)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	struct sk_buff *rgb_skb = NULL;
44862306a36Sopenharmony_ci	int r;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	r = nfc_hci_get_param(hdev, target->hci_reader_gate,
45162306a36Sopenharmony_ci				PN544_DEP_ATR_RES, &rgb_skb);
45262306a36Sopenharmony_ci	if (r < 0)
45362306a36Sopenharmony_ci		return r;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (rgb_skb->len == 0 || rgb_skb->len > NFC_GB_MAXSIZE) {
45662306a36Sopenharmony_ci		r = -EPROTO;
45762306a36Sopenharmony_ci		goto exit;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "remote gb: ", DUMP_PREFIX_OFFSET,
46062306a36Sopenharmony_ci			16, 1, rgb_skb->data, rgb_skb->len, true);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	r = nfc_set_remote_general_bytes(hdev->ndev, rgb_skb->data,
46362306a36Sopenharmony_ci						rgb_skb->len);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	if (r == 0)
46662306a36Sopenharmony_ci		r = nfc_dep_link_is_up(hdev->ndev, target->idx, comm_mode,
46762306a36Sopenharmony_ci					NFC_RF_INITIATOR);
46862306a36Sopenharmony_ciexit:
46962306a36Sopenharmony_ci	kfree_skb(rgb_skb);
47062306a36Sopenharmony_ci	return r;
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic int pn544_hci_dep_link_down(struct nfc_hci_dev *hdev)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_INITIATOR_GATE,
47762306a36Sopenharmony_ci					NFC_HCI_EVT_END_OPERATION, NULL, 0);
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_cistatic int pn544_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
48162306a36Sopenharmony_ci				      struct nfc_target *target)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	switch (gate) {
48462306a36Sopenharmony_ci	case PN544_RF_READER_F_GATE:
48562306a36Sopenharmony_ci		target->supported_protocols = NFC_PROTO_FELICA_MASK;
48662306a36Sopenharmony_ci		break;
48762306a36Sopenharmony_ci	case PN544_RF_READER_JEWEL_GATE:
48862306a36Sopenharmony_ci		target->supported_protocols = NFC_PROTO_JEWEL_MASK;
48962306a36Sopenharmony_ci		target->sens_res = 0x0c00;
49062306a36Sopenharmony_ci		break;
49162306a36Sopenharmony_ci	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
49262306a36Sopenharmony_ci		target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	default:
49562306a36Sopenharmony_ci		return -EPROTO;
49662306a36Sopenharmony_ci	}
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return 0;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
50262306a36Sopenharmony_ci						u8 gate,
50362306a36Sopenharmony_ci						struct nfc_target *target)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	struct sk_buff *uid_skb;
50662306a36Sopenharmony_ci	int r = 0;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE)
50962306a36Sopenharmony_ci		return r;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
51262306a36Sopenharmony_ci		r = nfc_hci_send_cmd(hdev,
51362306a36Sopenharmony_ci			PN544_RF_READER_NFCIP1_INITIATOR_GATE,
51462306a36Sopenharmony_ci			PN544_HCI_CMD_CONTINUE_ACTIVATION, NULL, 0, NULL);
51562306a36Sopenharmony_ci		if (r < 0)
51662306a36Sopenharmony_ci			return r;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
51962306a36Sopenharmony_ci	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
52062306a36Sopenharmony_ci		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
52162306a36Sopenharmony_ci		    target->nfcid1_len != 10)
52262306a36Sopenharmony_ci			return -EPROTO;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
52562306a36Sopenharmony_ci				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
52662306a36Sopenharmony_ci				     target->nfcid1, target->nfcid1_len, NULL);
52762306a36Sopenharmony_ci	} else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
52862306a36Sopenharmony_ci		r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE,
52962306a36Sopenharmony_ci				      PN544_FELICA_ID, &uid_skb);
53062306a36Sopenharmony_ci		if (r < 0)
53162306a36Sopenharmony_ci			return r;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		if (uid_skb->len != 8) {
53462306a36Sopenharmony_ci			kfree_skb(uid_skb);
53562306a36Sopenharmony_ci			return -EPROTO;
53662306a36Sopenharmony_ci		}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci		/* Type F NFC-DEP IDm has prefix 0x01FE */
53962306a36Sopenharmony_ci		if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) {
54062306a36Sopenharmony_ci			kfree_skb(uid_skb);
54162306a36Sopenharmony_ci			r = nfc_hci_send_cmd(hdev,
54262306a36Sopenharmony_ci					PN544_RF_READER_NFCIP1_INITIATOR_GATE,
54362306a36Sopenharmony_ci					PN544_HCI_CMD_CONTINUE_ACTIVATION,
54462306a36Sopenharmony_ci					NULL, 0, NULL);
54562306a36Sopenharmony_ci			if (r < 0)
54662306a36Sopenharmony_ci				return r;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci			target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
54962306a36Sopenharmony_ci			target->hci_reader_gate =
55062306a36Sopenharmony_ci				PN544_RF_READER_NFCIP1_INITIATOR_GATE;
55162306a36Sopenharmony_ci		} else {
55262306a36Sopenharmony_ci			r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
55362306a36Sopenharmony_ci					     PN544_RF_READER_CMD_ACTIVATE_NEXT,
55462306a36Sopenharmony_ci					     uid_skb->data, uid_skb->len, NULL);
55562306a36Sopenharmony_ci			kfree_skb(uid_skb);
55662306a36Sopenharmony_ci		}
55762306a36Sopenharmony_ci	} else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
55862306a36Sopenharmony_ci		/*
55962306a36Sopenharmony_ci		 * TODO: maybe other ISO 14443 require some kind of continue
56062306a36Sopenharmony_ci		 * activation, but for now we've seen only this one below.
56162306a36Sopenharmony_ci		 */
56262306a36Sopenharmony_ci		if (target->sens_res == 0x4403)	/* Type 4 Mifare DESFire */
56362306a36Sopenharmony_ci			r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
56462306a36Sopenharmony_ci			      PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION,
56562306a36Sopenharmony_ci			      NULL, 0, NULL);
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	return r;
56962306a36Sopenharmony_ci}
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci#define PN544_CB_TYPE_READER_F 1
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic void pn544_hci_data_exchange_cb(void *context, struct sk_buff *skb,
57462306a36Sopenharmony_ci				       int err)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct pn544_hci_info *info = context;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	switch (info->async_cb_type) {
57962306a36Sopenharmony_ci	case PN544_CB_TYPE_READER_F:
58062306a36Sopenharmony_ci		if (err == 0)
58162306a36Sopenharmony_ci			skb_pull(skb, 1);
58262306a36Sopenharmony_ci		info->async_cb(info->async_cb_context, skb, err);
58362306a36Sopenharmony_ci		break;
58462306a36Sopenharmony_ci	default:
58562306a36Sopenharmony_ci		if (err == 0)
58662306a36Sopenharmony_ci			kfree_skb(skb);
58762306a36Sopenharmony_ci		break;
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci#define MIFARE_CMD_AUTH_KEY_A	0x60
59262306a36Sopenharmony_ci#define MIFARE_CMD_AUTH_KEY_B	0x61
59362306a36Sopenharmony_ci#define MIFARE_CMD_HEADER	2
59462306a36Sopenharmony_ci#define MIFARE_UID_LEN		4
59562306a36Sopenharmony_ci#define MIFARE_KEY_LEN		6
59662306a36Sopenharmony_ci#define MIFARE_CMD_LEN		12
59762306a36Sopenharmony_ci/*
59862306a36Sopenharmony_ci * Returns:
59962306a36Sopenharmony_ci * <= 0: driver handled the data exchange
60062306a36Sopenharmony_ci *    1: driver doesn't especially handle, please do standard processing
60162306a36Sopenharmony_ci */
60262306a36Sopenharmony_cistatic int pn544_hci_im_transceive(struct nfc_hci_dev *hdev,
60362306a36Sopenharmony_ci				   struct nfc_target *target,
60462306a36Sopenharmony_ci				   struct sk_buff *skb, data_exchange_cb_t cb,
60562306a36Sopenharmony_ci				   void *cb_context)
60662306a36Sopenharmony_ci{
60762306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__,
61062306a36Sopenharmony_ci		target->hci_reader_gate);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	switch (target->hci_reader_gate) {
61362306a36Sopenharmony_ci	case NFC_HCI_RF_READER_A_GATE:
61462306a36Sopenharmony_ci		if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
61562306a36Sopenharmony_ci			/*
61662306a36Sopenharmony_ci			 * It seems that pn544 is inverting key and UID for
61762306a36Sopenharmony_ci			 * MIFARE authentication commands.
61862306a36Sopenharmony_ci			 */
61962306a36Sopenharmony_ci			if (skb->len == MIFARE_CMD_LEN &&
62062306a36Sopenharmony_ci			    (skb->data[0] == MIFARE_CMD_AUTH_KEY_A ||
62162306a36Sopenharmony_ci			     skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) {
62262306a36Sopenharmony_ci				u8 uid[MIFARE_UID_LEN];
62362306a36Sopenharmony_ci				u8 *data = skb->data + MIFARE_CMD_HEADER;
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci				memcpy(uid, data + MIFARE_KEY_LEN,
62662306a36Sopenharmony_ci				       MIFARE_UID_LEN);
62762306a36Sopenharmony_ci				memmove(data + MIFARE_UID_LEN, data,
62862306a36Sopenharmony_ci					MIFARE_KEY_LEN);
62962306a36Sopenharmony_ci				memcpy(data, uid, MIFARE_UID_LEN);
63062306a36Sopenharmony_ci			}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci			return nfc_hci_send_cmd_async(hdev,
63362306a36Sopenharmony_ci						      target->hci_reader_gate,
63462306a36Sopenharmony_ci						      PN544_MIFARE_CMD,
63562306a36Sopenharmony_ci						      skb->data, skb->len,
63662306a36Sopenharmony_ci						      cb, cb_context);
63762306a36Sopenharmony_ci		} else
63862306a36Sopenharmony_ci			return 1;
63962306a36Sopenharmony_ci	case PN544_RF_READER_F_GATE:
64062306a36Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0;
64162306a36Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci		info->async_cb_type = PN544_CB_TYPE_READER_F;
64462306a36Sopenharmony_ci		info->async_cb = cb;
64562306a36Sopenharmony_ci		info->async_cb_context = cb_context;
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
64862306a36Sopenharmony_ci					      PN544_FELICA_RAW, skb->data,
64962306a36Sopenharmony_ci					      skb->len,
65062306a36Sopenharmony_ci					      pn544_hci_data_exchange_cb, info);
65162306a36Sopenharmony_ci	case PN544_RF_READER_JEWEL_GATE:
65262306a36Sopenharmony_ci		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
65362306a36Sopenharmony_ci					      PN544_JEWEL_RAW_CMD, skb->data,
65462306a36Sopenharmony_ci					      skb->len, cb, cb_context);
65562306a36Sopenharmony_ci	case PN544_RF_READER_NFCIP1_INITIATOR_GATE:
65662306a36Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci		return nfc_hci_send_event(hdev, target->hci_reader_gate,
65962306a36Sopenharmony_ci					PN544_HCI_EVT_SND_DATA, skb->data,
66062306a36Sopenharmony_ci					skb->len);
66162306a36Sopenharmony_ci	default:
66262306a36Sopenharmony_ci		return 1;
66362306a36Sopenharmony_ci	}
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
66762306a36Sopenharmony_ci{
66862306a36Sopenharmony_ci	int r;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	/* Set default false for multiple information chaining */
67162306a36Sopenharmony_ci	*(u8 *)skb_push(skb, 1) = 0;
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	r = nfc_hci_send_event(hdev, PN544_RF_READER_NFCIP1_TARGET_GATE,
67462306a36Sopenharmony_ci			       PN544_HCI_EVT_SND_DATA, skb->data, skb->len);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	kfree_skb(skb);
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	return r;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
68262306a36Sopenharmony_ci				   struct nfc_target *target)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	pr_debug("supported protocol %d\n", target->supported_protocols);
68562306a36Sopenharmony_ci	if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
68662306a36Sopenharmony_ci					NFC_PROTO_ISO14443_B_MASK)) {
68762306a36Sopenharmony_ci		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
68862306a36Sopenharmony_ci					PN544_RF_READER_CMD_PRESENCE_CHECK,
68962306a36Sopenharmony_ci					NULL, 0, NULL);
69062306a36Sopenharmony_ci	} else if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) {
69162306a36Sopenharmony_ci		if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
69262306a36Sopenharmony_ci		    target->nfcid1_len != 10)
69362306a36Sopenharmony_ci			return -EOPNOTSUPP;
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci		return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
69662306a36Sopenharmony_ci				     PN544_RF_READER_CMD_ACTIVATE_NEXT,
69762306a36Sopenharmony_ci				     target->nfcid1, target->nfcid1_len, NULL);
69862306a36Sopenharmony_ci	} else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
69962306a36Sopenharmony_ci						NFC_PROTO_FELICA_MASK)) {
70062306a36Sopenharmony_ci		return -EOPNOTSUPP;
70162306a36Sopenharmony_ci	} else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
70262306a36Sopenharmony_ci		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
70362306a36Sopenharmony_ci					PN544_HCI_CMD_ATTREQUEST,
70462306a36Sopenharmony_ci					NULL, 0, NULL);
70562306a36Sopenharmony_ci	}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	return 0;
70862306a36Sopenharmony_ci}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci/*
71162306a36Sopenharmony_ci * Returns:
71262306a36Sopenharmony_ci * <= 0: driver handled the event, skb consumed
71362306a36Sopenharmony_ci *    1: driver does not handle the event, please do standard processing
71462306a36Sopenharmony_ci */
71562306a36Sopenharmony_cistatic int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
71662306a36Sopenharmony_ci				    struct sk_buff *skb)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	struct sk_buff *rgb_skb = NULL;
71962306a36Sopenharmony_ci	u8 gate = hdev->pipes[pipe].gate;
72062306a36Sopenharmony_ci	int r;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	pr_debug("hci event %d\n", event);
72362306a36Sopenharmony_ci	switch (event) {
72462306a36Sopenharmony_ci	case PN544_HCI_EVT_ACTIVATED:
72562306a36Sopenharmony_ci		if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
72662306a36Sopenharmony_ci			r = nfc_hci_target_discovered(hdev, gate);
72762306a36Sopenharmony_ci		} else if (gate == PN544_RF_READER_NFCIP1_TARGET_GATE) {
72862306a36Sopenharmony_ci			r = nfc_hci_get_param(hdev, gate, PN544_DEP_ATR_REQ,
72962306a36Sopenharmony_ci					      &rgb_skb);
73062306a36Sopenharmony_ci			if (r < 0)
73162306a36Sopenharmony_ci				goto exit;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci			r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
73462306a36Sopenharmony_ci					     NFC_COMM_PASSIVE, rgb_skb->data,
73562306a36Sopenharmony_ci					     rgb_skb->len);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci			kfree_skb(rgb_skb);
73862306a36Sopenharmony_ci		} else {
73962306a36Sopenharmony_ci			r = -EINVAL;
74062306a36Sopenharmony_ci		}
74162306a36Sopenharmony_ci		break;
74262306a36Sopenharmony_ci	case PN544_HCI_EVT_DEACTIVATED:
74362306a36Sopenharmony_ci		r = nfc_hci_send_event(hdev, gate, NFC_HCI_EVT_END_OPERATION,
74462306a36Sopenharmony_ci				       NULL, 0);
74562306a36Sopenharmony_ci		break;
74662306a36Sopenharmony_ci	case PN544_HCI_EVT_RCV_DATA:
74762306a36Sopenharmony_ci		if (skb->len < 2) {
74862306a36Sopenharmony_ci			r = -EPROTO;
74962306a36Sopenharmony_ci			goto exit;
75062306a36Sopenharmony_ci		}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		if (skb->data[0] != 0) {
75362306a36Sopenharmony_ci			pr_debug("data0 %d\n", skb->data[0]);
75462306a36Sopenharmony_ci			r = -EPROTO;
75562306a36Sopenharmony_ci			goto exit;
75662306a36Sopenharmony_ci		}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci		skb_pull(skb, 2);
75962306a36Sopenharmony_ci		return nfc_tm_data_received(hdev->ndev, skb);
76062306a36Sopenharmony_ci	default:
76162306a36Sopenharmony_ci		return 1;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ciexit:
76562306a36Sopenharmony_ci	kfree_skb(skb);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	return r;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
77162306a36Sopenharmony_ci				 const char *firmware_name)
77262306a36Sopenharmony_ci{
77362306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	if (info->fw_download == NULL)
77662306a36Sopenharmony_ci		return -ENOTSUPP;
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib);
77962306a36Sopenharmony_ci}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_cistatic int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
78262306a36Sopenharmony_ci{
78362306a36Sopenharmony_ci	u32 se_idx = 0;
78462306a36Sopenharmony_ci	u8 ese_mode = 0x01; /* Default mode */
78562306a36Sopenharmony_ci	struct sk_buff *res_skb;
78662306a36Sopenharmony_ci	int r;
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP,
78962306a36Sopenharmony_ci			     NULL, 0, &res_skb);
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	if (r == 0) {
79262306a36Sopenharmony_ci		if (res_skb->len == 2 && res_skb->data[0] == 0x00)
79362306a36Sopenharmony_ci			nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		kfree_skb(res_skb);
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE,
79962306a36Sopenharmony_ci				PN544_HCI_EVT_SWITCH_MODE,
80062306a36Sopenharmony_ci				&ese_mode, 1);
80162306a36Sopenharmony_ci	if (r == 0)
80262306a36Sopenharmony_ci		nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci	return !se_idx;
80562306a36Sopenharmony_ci}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci#define PN544_SE_MODE_OFF	0x00
80862306a36Sopenharmony_ci#define PN544_SE_MODE_ON	0x01
80962306a36Sopenharmony_cistatic int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
81062306a36Sopenharmony_ci{
81162306a36Sopenharmony_ci	const struct nfc_se *se;
81262306a36Sopenharmony_ci	u8 enable = PN544_SE_MODE_ON;
81362306a36Sopenharmony_ci	static struct uicc_gatelist {
81462306a36Sopenharmony_ci		u8 head;
81562306a36Sopenharmony_ci		u8 adr[2];
81662306a36Sopenharmony_ci		u8 value;
81762306a36Sopenharmony_ci	} uicc_gatelist[] = {
81862306a36Sopenharmony_ci		{0x00, {0x9e, 0xd9}, 0x23},
81962306a36Sopenharmony_ci		{0x00, {0x9e, 0xda}, 0x21},
82062306a36Sopenharmony_ci		{0x00, {0x9e, 0xdb}, 0x22},
82162306a36Sopenharmony_ci		{0x00, {0x9e, 0xdc}, 0x24},
82262306a36Sopenharmony_ci	};
82362306a36Sopenharmony_ci	struct uicc_gatelist *p = uicc_gatelist;
82462306a36Sopenharmony_ci	int count = ARRAY_SIZE(uicc_gatelist);
82562306a36Sopenharmony_ci	struct sk_buff *res_skb;
82662306a36Sopenharmony_ci	int r;
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	se = nfc_find_se(hdev->ndev, se_idx);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	switch (se->type) {
83162306a36Sopenharmony_ci	case NFC_SE_UICC:
83262306a36Sopenharmony_ci		while (count--) {
83362306a36Sopenharmony_ci			r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE,
83462306a36Sopenharmony_ci					PN544_WRITE, (u8 *)p, 4, &res_skb);
83562306a36Sopenharmony_ci			if (r < 0)
83662306a36Sopenharmony_ci				return r;
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci			if (res_skb->len != 1) {
83962306a36Sopenharmony_ci				kfree_skb(res_skb);
84062306a36Sopenharmony_ci				return -EPROTO;
84162306a36Sopenharmony_ci			}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci			if (res_skb->data[0] != p->value) {
84462306a36Sopenharmony_ci				kfree_skb(res_skb);
84562306a36Sopenharmony_ci				return -EIO;
84662306a36Sopenharmony_ci			}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci			kfree_skb(res_skb);
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci			p++;
85162306a36Sopenharmony_ci		}
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci		return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
85462306a36Sopenharmony_ci			      PN544_SWP_DEFAULT_MODE, &enable, 1);
85562306a36Sopenharmony_ci	case NFC_SE_EMBEDDED:
85662306a36Sopenharmony_ci		return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
85762306a36Sopenharmony_ci			      PN544_NFC_ESE_DEFAULT_MODE, &enable, 1);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	default:
86062306a36Sopenharmony_ci		return -EINVAL;
86162306a36Sopenharmony_ci	}
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	const struct nfc_se *se;
86762306a36Sopenharmony_ci	u8 disable = PN544_SE_MODE_OFF;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	se = nfc_find_se(hdev->ndev, se_idx);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	switch (se->type) {
87262306a36Sopenharmony_ci	case NFC_SE_UICC:
87362306a36Sopenharmony_ci		return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
87462306a36Sopenharmony_ci			      PN544_SWP_DEFAULT_MODE, &disable, 1);
87562306a36Sopenharmony_ci	case NFC_SE_EMBEDDED:
87662306a36Sopenharmony_ci		return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
87762306a36Sopenharmony_ci			      PN544_NFC_ESE_DEFAULT_MODE, &disable, 1);
87862306a36Sopenharmony_ci	default:
87962306a36Sopenharmony_ci		return -EINVAL;
88062306a36Sopenharmony_ci	}
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic const struct nfc_hci_ops pn544_hci_ops = {
88462306a36Sopenharmony_ci	.open = pn544_hci_open,
88562306a36Sopenharmony_ci	.close = pn544_hci_close,
88662306a36Sopenharmony_ci	.hci_ready = pn544_hci_ready,
88762306a36Sopenharmony_ci	.xmit = pn544_hci_xmit,
88862306a36Sopenharmony_ci	.start_poll = pn544_hci_start_poll,
88962306a36Sopenharmony_ci	.dep_link_up = pn544_hci_dep_link_up,
89062306a36Sopenharmony_ci	.dep_link_down = pn544_hci_dep_link_down,
89162306a36Sopenharmony_ci	.target_from_gate = pn544_hci_target_from_gate,
89262306a36Sopenharmony_ci	.complete_target_discovered = pn544_hci_complete_target_discovered,
89362306a36Sopenharmony_ci	.im_transceive = pn544_hci_im_transceive,
89462306a36Sopenharmony_ci	.tm_send = pn544_hci_tm_send,
89562306a36Sopenharmony_ci	.check_presence = pn544_hci_check_presence,
89662306a36Sopenharmony_ci	.event_received = pn544_hci_event_received,
89762306a36Sopenharmony_ci	.fw_download = pn544_hci_fw_download,
89862306a36Sopenharmony_ci	.discover_se = pn544_hci_discover_se,
89962306a36Sopenharmony_ci	.enable_se = pn544_hci_enable_se,
90062306a36Sopenharmony_ci	.disable_se = pn544_hci_disable_se,
90162306a36Sopenharmony_ci};
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ciint pn544_hci_probe(void *phy_id, const struct nfc_phy_ops *phy_ops,
90462306a36Sopenharmony_ci		    char *llc_name, int phy_headroom, int phy_tailroom,
90562306a36Sopenharmony_ci		    int phy_payload, fw_download_t fw_download,
90662306a36Sopenharmony_ci		    struct nfc_hci_dev **hdev)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	struct pn544_hci_info *info;
90962306a36Sopenharmony_ci	u32 protocols;
91062306a36Sopenharmony_ci	struct nfc_hci_init_data init_data;
91162306a36Sopenharmony_ci	int r;
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
91462306a36Sopenharmony_ci	if (!info) {
91562306a36Sopenharmony_ci		r = -ENOMEM;
91662306a36Sopenharmony_ci		goto err_info_alloc;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	info->phy_ops = phy_ops;
92062306a36Sopenharmony_ci	info->phy_id = phy_id;
92162306a36Sopenharmony_ci	info->fw_download = fw_download;
92262306a36Sopenharmony_ci	info->state = PN544_ST_COLD;
92362306a36Sopenharmony_ci	mutex_init(&info->info_lock);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	init_data.gate_count = ARRAY_SIZE(pn544_gates);
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates));
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/*
93062306a36Sopenharmony_ci	 * TODO: Session id must include the driver name + some bus addr
93162306a36Sopenharmony_ci	 * persistent info to discriminate 2 identical chips
93262306a36Sopenharmony_ci	 */
93362306a36Sopenharmony_ci	strcpy(init_data.session_id, "ID544HCI");
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	protocols = NFC_PROTO_JEWEL_MASK |
93662306a36Sopenharmony_ci		    NFC_PROTO_MIFARE_MASK |
93762306a36Sopenharmony_ci		    NFC_PROTO_FELICA_MASK |
93862306a36Sopenharmony_ci		    NFC_PROTO_ISO14443_MASK |
93962306a36Sopenharmony_ci		    NFC_PROTO_ISO14443_B_MASK |
94062306a36Sopenharmony_ci		    NFC_PROTO_NFC_DEP_MASK;
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
94362306a36Sopenharmony_ci					     protocols, llc_name,
94462306a36Sopenharmony_ci					     phy_headroom + PN544_CMDS_HEADROOM,
94562306a36Sopenharmony_ci					     phy_tailroom, phy_payload);
94662306a36Sopenharmony_ci	if (!info->hdev) {
94762306a36Sopenharmony_ci		pr_err("Cannot allocate nfc hdev\n");
94862306a36Sopenharmony_ci		r = -ENOMEM;
94962306a36Sopenharmony_ci		goto err_alloc_hdev;
95062306a36Sopenharmony_ci	}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	nfc_hci_set_clientdata(info->hdev, info);
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	r = nfc_hci_register_device(info->hdev);
95562306a36Sopenharmony_ci	if (r)
95662306a36Sopenharmony_ci		goto err_regdev;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	*hdev = info->hdev;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	return 0;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cierr_regdev:
96362306a36Sopenharmony_ci	nfc_hci_free_device(info->hdev);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_cierr_alloc_hdev:
96662306a36Sopenharmony_ci	kfree(info);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_cierr_info_alloc:
96962306a36Sopenharmony_ci	return r;
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ciEXPORT_SYMBOL(pn544_hci_probe);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_civoid pn544_hci_remove(struct nfc_hci_dev *hdev)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct pn544_hci_info *info = nfc_hci_get_clientdata(hdev);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	nfc_hci_unregister_device(hdev);
97862306a36Sopenharmony_ci	nfc_hci_free_device(hdev);
97962306a36Sopenharmony_ci	kfree(info);
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ciEXPORT_SYMBOL(pn544_hci_remove);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ciMODULE_LICENSE("GPL");
98462306a36Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
985