18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * HCI based Driver for STMicroelectronics NFC Chip
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2014  STMicroelectronics SAS. All rights reserved.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/nfc.h>
108c2ecf20Sopenharmony_ci#include <net/nfc/hci.h>
118c2ecf20Sopenharmony_ci#include <net/nfc/llc.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include "st21nfca.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define DRIVER_DESC "HCI NFC driver for ST21NFCA"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define FULL_VERSION_LEN 3
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/* Proprietary gates, events, commands and registers */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* Commands that apply to all RF readers */
228c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_CMD_PRESENCE_CHECK	0x30
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_ISO15693_GATE	0x12
258c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_ISO15693_INVENTORY	0x01
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci/*
288c2ecf20Sopenharmony_ci * Reader gate for communication with contact-less cards using Type A
298c2ecf20Sopenharmony_ci * protocol ISO14443-3 but not compliant with ISO14443-4
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_14443_3_A_GATE	0x15
328c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_14443_3_A_UID	0x02
338c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_14443_3_A_ATQA	0x03
348c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_14443_3_A_SAK	0x04
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_DATARATE		0x01
378c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_DATARATE_106	0x01
388c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_DATARATE_212	0x02
398c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_DATARATE_424	0x04
408c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_POL_REQ		0x02
418c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_POL_REQ_DEFAULT	0xffff0000
428c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_NFCID2		0x03
438c2ecf20Sopenharmony_ci#define ST21NFCA_RF_READER_F_NFCID1		0x04
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_MODE			0x01
468c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_NFCID2_LIST		0x04
478c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_NFCID1		0x05
488c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_SENS_RES		0x06
498c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_SEL_RES		0x07
508c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_DATARATE		0x08
518c2ecf20Sopenharmony_ci#define ST21NFCA_RF_CARD_F_DATARATE_212_424	0x01
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define ST21NFCA_DEVICE_MGNT_PIPE		0x02
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci#define ST21NFCA_DM_GETINFO			0x13
568c2ecf20Sopenharmony_ci#define ST21NFCA_DM_GETINFO_PIPE_LIST		0x02
578c2ecf20Sopenharmony_ci#define ST21NFCA_DM_GETINFO_PIPE_INFO		0x01
588c2ecf20Sopenharmony_ci#define ST21NFCA_DM_PIPE_CREATED		0x02
598c2ecf20Sopenharmony_ci#define ST21NFCA_DM_PIPE_OPEN			0x04
608c2ecf20Sopenharmony_ci#define ST21NFCA_DM_RF_ACTIVE			0x80
618c2ecf20Sopenharmony_ci#define ST21NFCA_DM_DISCONNECT			0x30
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define ST21NFCA_DM_IS_PIPE_OPEN(p) \
648c2ecf20Sopenharmony_ci	((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN))
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define ST21NFCA_NFC_MODE			0x03	/* NFC_MODE parameter*/
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#define ST21NFCA_EVT_HOT_PLUG			0x03
698c2ecf20Sopenharmony_ci#define ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define ST21NFCA_SE_TO_PIPES			2000
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic struct nfc_hci_gate st21nfca_gates[] = {
768c2ecf20Sopenharmony_ci	{NFC_HCI_ADMIN_GATE, NFC_HCI_ADMIN_PIPE},
778c2ecf20Sopenharmony_ci	{NFC_HCI_LINK_MGMT_GATE, NFC_HCI_LINK_MGMT_PIPE},
788c2ecf20Sopenharmony_ci	{ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE},
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	{NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE},
818c2ecf20Sopenharmony_ci	{NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE},
828c2ecf20Sopenharmony_ci	{NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE},
838c2ecf20Sopenharmony_ci	{NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE},
848c2ecf20Sopenharmony_ci	{ST21NFCA_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE},
858c2ecf20Sopenharmony_ci	{ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
868c2ecf20Sopenharmony_ci	{ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
878c2ecf20Sopenharmony_ci	{ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE},
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* Secure element pipes are created by secure element host */
908c2ecf20Sopenharmony_ci	{ST21NFCA_CONNECTIVITY_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
918c2ecf20Sopenharmony_ci	{ST21NFCA_APDU_READER_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
928c2ecf20Sopenharmony_ci};
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistruct st21nfca_pipe_info {
958c2ecf20Sopenharmony_ci	u8 pipe_state;
968c2ecf20Sopenharmony_ci	u8 src_host_id;
978c2ecf20Sopenharmony_ci	u8 src_gate_id;
988c2ecf20Sopenharmony_ci	u8 dst_host_id;
998c2ecf20Sopenharmony_ci	u8 dst_gate_id;
1008c2ecf20Sopenharmony_ci} __packed;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci/* Largest headroom needed for outgoing custom commands */
1038c2ecf20Sopenharmony_ci#define ST21NFCA_CMDS_HEADROOM  7
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	int i, j, r;
1088c2ecf20Sopenharmony_ci	struct sk_buff *skb_pipe_list, *skb_pipe_info;
1098c2ecf20Sopenharmony_ci	struct st21nfca_pipe_info *info;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	u8 pipe_list[] = { ST21NFCA_DM_GETINFO_PIPE_LIST,
1128c2ecf20Sopenharmony_ci		NFC_HCI_TERMINAL_HOST_ID
1138c2ecf20Sopenharmony_ci	};
1148c2ecf20Sopenharmony_ci	u8 pipe_info[] = { ST21NFCA_DM_GETINFO_PIPE_INFO,
1158c2ecf20Sopenharmony_ci		NFC_HCI_TERMINAL_HOST_ID, 0
1168c2ecf20Sopenharmony_ci	};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* On ST21NFCA device pipes number are dynamics
1198c2ecf20Sopenharmony_ci	 * A maximum of 16 pipes can be created at the same time
1208c2ecf20Sopenharmony_ci	 * If pipes are already created, hci_dev_up will fail.
1218c2ecf20Sopenharmony_ci	 * Doing a clear all pipe is a bad idea because:
1228c2ecf20Sopenharmony_ci	 * - It does useless EEPROM cycling
1238c2ecf20Sopenharmony_ci	 * - It might cause issue for secure elements support
1248c2ecf20Sopenharmony_ci	 * (such as removing connectivity or APDU reader pipe)
1258c2ecf20Sopenharmony_ci	 * A better approach on ST21NFCA is to:
1268c2ecf20Sopenharmony_ci	 * - get a pipe list for each host.
1278c2ecf20Sopenharmony_ci	 * (eg: NFC_HCI_HOST_CONTROLLER_ID for now).
1288c2ecf20Sopenharmony_ci	 * (TODO Later on UICC HOST and eSE HOST)
1298c2ecf20Sopenharmony_ci	 * - get pipe information
1308c2ecf20Sopenharmony_ci	 * - match retrieved pipe list in st21nfca_gates
1318c2ecf20Sopenharmony_ci	 * ST21NFCA_DEVICE_MGNT_GATE is a proprietary gate
1328c2ecf20Sopenharmony_ci	 * with ST21NFCA_DEVICE_MGNT_PIPE.
1338c2ecf20Sopenharmony_ci	 * Pipe can be closed and need to be open.
1348c2ecf20Sopenharmony_ci	 */
1358c2ecf20Sopenharmony_ci	r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
1368c2ecf20Sopenharmony_ci				ST21NFCA_DEVICE_MGNT_GATE,
1378c2ecf20Sopenharmony_ci				ST21NFCA_DEVICE_MGNT_PIPE);
1388c2ecf20Sopenharmony_ci	if (r < 0)
1398c2ecf20Sopenharmony_ci		return r;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	/* Get pipe list */
1428c2ecf20Sopenharmony_ci	r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
1438c2ecf20Sopenharmony_ci			ST21NFCA_DM_GETINFO, pipe_list, sizeof(pipe_list),
1448c2ecf20Sopenharmony_ci			&skb_pipe_list);
1458c2ecf20Sopenharmony_ci	if (r < 0)
1468c2ecf20Sopenharmony_ci		return r;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	/* Complete the existing gate_pipe table */
1498c2ecf20Sopenharmony_ci	for (i = 0; i < skb_pipe_list->len; i++) {
1508c2ecf20Sopenharmony_ci		pipe_info[2] = skb_pipe_list->data[i];
1518c2ecf20Sopenharmony_ci		r = nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
1528c2ecf20Sopenharmony_ci					ST21NFCA_DM_GETINFO, pipe_info,
1538c2ecf20Sopenharmony_ci					sizeof(pipe_info), &skb_pipe_info);
1548c2ecf20Sopenharmony_ci		if (r)
1558c2ecf20Sopenharmony_ci			continue;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		/*
1588c2ecf20Sopenharmony_ci		 * Match pipe ID and gate ID
1598c2ecf20Sopenharmony_ci		 * Output format from ST21NFC_DM_GETINFO is:
1608c2ecf20Sopenharmony_ci		 * - pipe state (1byte)
1618c2ecf20Sopenharmony_ci		 * - source hid (1byte)
1628c2ecf20Sopenharmony_ci		 * - source gid (1byte)
1638c2ecf20Sopenharmony_ci		 * - destination hid (1byte)
1648c2ecf20Sopenharmony_ci		 * - destination gid (1byte)
1658c2ecf20Sopenharmony_ci		 */
1668c2ecf20Sopenharmony_ci		info = (struct st21nfca_pipe_info *) skb_pipe_info->data;
1678c2ecf20Sopenharmony_ci		if (info->dst_gate_id == ST21NFCA_APDU_READER_GATE &&
1688c2ecf20Sopenharmony_ci			info->src_host_id == NFC_HCI_UICC_HOST_ID) {
1698c2ecf20Sopenharmony_ci			pr_err("Unexpected apdu_reader pipe on host %x\n",
1708c2ecf20Sopenharmony_ci				info->src_host_id);
1718c2ecf20Sopenharmony_ci			kfree_skb(skb_pipe_info);
1728c2ecf20Sopenharmony_ci			continue;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		for (j = 3; (j < ARRAY_SIZE(st21nfca_gates)) &&
1768c2ecf20Sopenharmony_ci			(st21nfca_gates[j].gate != info->dst_gate_id) ; j++)
1778c2ecf20Sopenharmony_ci			;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci		if (j < ARRAY_SIZE(st21nfca_gates) &&
1808c2ecf20Sopenharmony_ci			st21nfca_gates[j].gate == info->dst_gate_id &&
1818c2ecf20Sopenharmony_ci			ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
1828c2ecf20Sopenharmony_ci			hdev->init_data.gates[j].pipe = pipe_info[2];
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci			hdev->gate2pipe[st21nfca_gates[j].gate] =
1858c2ecf20Sopenharmony_ci						pipe_info[2];
1868c2ecf20Sopenharmony_ci			hdev->pipes[pipe_info[2]].gate =
1878c2ecf20Sopenharmony_ci						st21nfca_gates[j].gate;
1888c2ecf20Sopenharmony_ci			hdev->pipes[pipe_info[2]].dest_host =
1898c2ecf20Sopenharmony_ci						info->src_host_id;
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci		kfree_skb(skb_pipe_info);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/*
1958c2ecf20Sopenharmony_ci	 * 3 gates have a well known pipe ID. Only NFC_HCI_LINK_MGMT_GATE
1968c2ecf20Sopenharmony_ci	 * is not yet open at this stage.
1978c2ecf20Sopenharmony_ci	 */
1988c2ecf20Sopenharmony_ci	r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
1998c2ecf20Sopenharmony_ci				 NFC_HCI_LINK_MGMT_GATE,
2008c2ecf20Sopenharmony_ci				 NFC_HCI_LINK_MGMT_PIPE);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	kfree_skb(skb_pipe_list);
2038c2ecf20Sopenharmony_ci	return r;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int st21nfca_hci_open(struct nfc_hci_dev *hdev)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
2098c2ecf20Sopenharmony_ci	int r;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	mutex_lock(&info->info_lock);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (info->state != ST21NFCA_ST_COLD) {
2148c2ecf20Sopenharmony_ci		r = -EBUSY;
2158c2ecf20Sopenharmony_ci		goto out;
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	r = info->phy_ops->enable(info->phy_id);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (r == 0)
2218c2ecf20Sopenharmony_ci		info->state = ST21NFCA_ST_READY;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ciout:
2248c2ecf20Sopenharmony_ci	mutex_unlock(&info->info_lock);
2258c2ecf20Sopenharmony_ci	return r;
2268c2ecf20Sopenharmony_ci}
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic void st21nfca_hci_close(struct nfc_hci_dev *hdev)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	mutex_lock(&info->info_lock);
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (info->state == ST21NFCA_ST_COLD)
2358c2ecf20Sopenharmony_ci		goto out;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	info->phy_ops->disable(info->phy_id);
2388c2ecf20Sopenharmony_ci	info->state = ST21NFCA_ST_COLD;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ciout:
2418c2ecf20Sopenharmony_ci	mutex_unlock(&info->info_lock);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
2478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	u8 param;
2508c2ecf20Sopenharmony_ci	u8 white_list[2];
2518c2ecf20Sopenharmony_ci	int wl_size = 0;
2528c2ecf20Sopenharmony_ci	int r;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (info->se_status->is_uicc_present)
2558c2ecf20Sopenharmony_ci		white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
2568c2ecf20Sopenharmony_ci	if (info->se_status->is_ese_present)
2578c2ecf20Sopenharmony_ci		white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (wl_size) {
2608c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
2618c2ecf20Sopenharmony_ci					NFC_HCI_ADMIN_WHITELIST,
2628c2ecf20Sopenharmony_ci					(u8 *) &white_list, wl_size);
2638c2ecf20Sopenharmony_ci		if (r < 0)
2648c2ecf20Sopenharmony_ci			return r;
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* Set NFC_MODE in device management gate to enable */
2688c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
2698c2ecf20Sopenharmony_ci			      ST21NFCA_NFC_MODE, &skb);
2708c2ecf20Sopenharmony_ci	if (r < 0)
2718c2ecf20Sopenharmony_ci		return r;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	param = skb->data[0];
2748c2ecf20Sopenharmony_ci	kfree_skb(skb);
2758c2ecf20Sopenharmony_ci	if (param == 0) {
2768c2ecf20Sopenharmony_ci		param = 1;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
2798c2ecf20Sopenharmony_ci					ST21NFCA_NFC_MODE, &param, 1);
2808c2ecf20Sopenharmony_ci		if (r < 0)
2818c2ecf20Sopenharmony_ci			return r;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
2858c2ecf20Sopenharmony_ci			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
2868c2ecf20Sopenharmony_ci	if (r < 0)
2878c2ecf20Sopenharmony_ci		return r;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
2908c2ecf20Sopenharmony_ci			      NFC_HCI_ID_MGMT_VERSION_SW, &skb);
2918c2ecf20Sopenharmony_ci	if (r < 0)
2928c2ecf20Sopenharmony_ci		return r;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (skb->len != FULL_VERSION_LEN) {
2958c2ecf20Sopenharmony_ci		kfree_skb(skb);
2968c2ecf20Sopenharmony_ci		return -EINVAL;
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ",
3008c2ecf20Sopenharmony_ci		       DUMP_PREFIX_NONE, 16, 1,
3018c2ecf20Sopenharmony_ci		       skb->data, FULL_VERSION_LEN, false);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	kfree_skb(skb);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	return 0;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int st21nfca_hci_xmit(struct nfc_hci_dev *hdev, struct sk_buff *skb)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return info->phy_ops->write(info->phy_id, skb);
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
3168c2ecf20Sopenharmony_ci				   u32 im_protocols, u32 tm_protocols)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	int r;
3198c2ecf20Sopenharmony_ci	u32 pol_req;
3208c2ecf20Sopenharmony_ci	u8 param[19];
3218c2ecf20Sopenharmony_ci	struct sk_buff *datarate_skb;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
3248c2ecf20Sopenharmony_ci		__func__, im_protocols, tm_protocols);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
3278c2ecf20Sopenharmony_ci			       NFC_HCI_EVT_END_OPERATION, NULL, 0);
3288c2ecf20Sopenharmony_ci	if (r < 0)
3298c2ecf20Sopenharmony_ci		return r;
3308c2ecf20Sopenharmony_ci	if (im_protocols) {
3318c2ecf20Sopenharmony_ci		/*
3328c2ecf20Sopenharmony_ci		 * enable polling according to im_protocols & tm_protocols
3338c2ecf20Sopenharmony_ci		 * - CLOSE pipe according to im_protocols & tm_protocols
3348c2ecf20Sopenharmony_ci		 */
3358c2ecf20Sopenharmony_ci		if ((NFC_HCI_RF_READER_B_GATE & im_protocols) == 0) {
3368c2ecf20Sopenharmony_ci			r = nfc_hci_disconnect_gate(hdev,
3378c2ecf20Sopenharmony_ci					NFC_HCI_RF_READER_B_GATE);
3388c2ecf20Sopenharmony_ci			if (r < 0)
3398c2ecf20Sopenharmony_ci				return r;
3408c2ecf20Sopenharmony_ci		}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		if ((NFC_HCI_RF_READER_A_GATE & im_protocols) == 0) {
3438c2ecf20Sopenharmony_ci			r = nfc_hci_disconnect_gate(hdev,
3448c2ecf20Sopenharmony_ci					NFC_HCI_RF_READER_A_GATE);
3458c2ecf20Sopenharmony_ci			if (r < 0)
3468c2ecf20Sopenharmony_ci				return r;
3478c2ecf20Sopenharmony_ci		}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci		if ((ST21NFCA_RF_READER_F_GATE & im_protocols) == 0) {
3508c2ecf20Sopenharmony_ci			r = nfc_hci_disconnect_gate(hdev,
3518c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_F_GATE);
3528c2ecf20Sopenharmony_ci			if (r < 0)
3538c2ecf20Sopenharmony_ci				return r;
3548c2ecf20Sopenharmony_ci		} else {
3558c2ecf20Sopenharmony_ci			hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
3568c2ecf20Sopenharmony_ci							       &hdev->gb_len);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci			if (hdev->gb == NULL || hdev->gb_len == 0) {
3598c2ecf20Sopenharmony_ci				im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
3608c2ecf20Sopenharmony_ci				tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
3618c2ecf20Sopenharmony_ci			}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci			param[0] = ST21NFCA_RF_READER_F_DATARATE_106 |
3648c2ecf20Sopenharmony_ci			    ST21NFCA_RF_READER_F_DATARATE_212 |
3658c2ecf20Sopenharmony_ci			    ST21NFCA_RF_READER_F_DATARATE_424;
3668c2ecf20Sopenharmony_ci			r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE,
3678c2ecf20Sopenharmony_ci					      ST21NFCA_RF_READER_F_DATARATE,
3688c2ecf20Sopenharmony_ci					      param, 1);
3698c2ecf20Sopenharmony_ci			if (r < 0)
3708c2ecf20Sopenharmony_ci				return r;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci			pol_req = be32_to_cpu((__force __be32)
3738c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_F_POL_REQ_DEFAULT);
3748c2ecf20Sopenharmony_ci			r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE,
3758c2ecf20Sopenharmony_ci					      ST21NFCA_RF_READER_F_POL_REQ,
3768c2ecf20Sopenharmony_ci					      (u8 *) &pol_req, 4);
3778c2ecf20Sopenharmony_ci			if (r < 0)
3788c2ecf20Sopenharmony_ci				return r;
3798c2ecf20Sopenharmony_ci		}
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci		if ((ST21NFCA_RF_READER_14443_3_A_GATE & im_protocols) == 0) {
3828c2ecf20Sopenharmony_ci			r = nfc_hci_disconnect_gate(hdev,
3838c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_14443_3_A_GATE);
3848c2ecf20Sopenharmony_ci			if (r < 0)
3858c2ecf20Sopenharmony_ci				return r;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci		if ((ST21NFCA_RF_READER_ISO15693_GATE & im_protocols) == 0) {
3898c2ecf20Sopenharmony_ci			r = nfc_hci_disconnect_gate(hdev,
3908c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_ISO15693_GATE);
3918c2ecf20Sopenharmony_ci			if (r < 0)
3928c2ecf20Sopenharmony_ci				return r;
3938c2ecf20Sopenharmony_ci		}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
3968c2ecf20Sopenharmony_ci				       NFC_HCI_EVT_READER_REQUESTED, NULL, 0);
3978c2ecf20Sopenharmony_ci		if (r < 0)
3988c2ecf20Sopenharmony_ci			nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
3998c2ecf20Sopenharmony_ci					   NFC_HCI_EVT_END_OPERATION, NULL, 0);
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
4038c2ecf20Sopenharmony_ci		r = nfc_hci_get_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4048c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_DATARATE,
4058c2ecf20Sopenharmony_ci				      &datarate_skb);
4068c2ecf20Sopenharmony_ci		if (r < 0)
4078c2ecf20Sopenharmony_ci			return r;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci		/* Configure the maximum supported datarate to 424Kbps */
4108c2ecf20Sopenharmony_ci		if (datarate_skb->len > 0 &&
4118c2ecf20Sopenharmony_ci		    datarate_skb->data[0] !=
4128c2ecf20Sopenharmony_ci		    ST21NFCA_RF_CARD_F_DATARATE_212_424) {
4138c2ecf20Sopenharmony_ci			param[0] = ST21NFCA_RF_CARD_F_DATARATE_212_424;
4148c2ecf20Sopenharmony_ci			r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4158c2ecf20Sopenharmony_ci					      ST21NFCA_RF_CARD_F_DATARATE,
4168c2ecf20Sopenharmony_ci					      param, 1);
4178c2ecf20Sopenharmony_ci			if (r < 0) {
4188c2ecf20Sopenharmony_ci				kfree_skb(datarate_skb);
4198c2ecf20Sopenharmony_ci				return r;
4208c2ecf20Sopenharmony_ci			}
4218c2ecf20Sopenharmony_ci		}
4228c2ecf20Sopenharmony_ci		kfree_skb(datarate_skb);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		/*
4258c2ecf20Sopenharmony_ci		 * Configure sens_res
4268c2ecf20Sopenharmony_ci		 *
4278c2ecf20Sopenharmony_ci		 * NFC Forum Digital Spec Table 7:
4288c2ecf20Sopenharmony_ci		 * NFCID1 size: triple (10 bytes)
4298c2ecf20Sopenharmony_ci		 */
4308c2ecf20Sopenharmony_ci		param[0] = 0x00;
4318c2ecf20Sopenharmony_ci		param[1] = 0x08;
4328c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4338c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_SENS_RES, param, 2);
4348c2ecf20Sopenharmony_ci		if (r < 0)
4358c2ecf20Sopenharmony_ci			return r;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		/*
4388c2ecf20Sopenharmony_ci		 * Configure sel_res
4398c2ecf20Sopenharmony_ci		 *
4408c2ecf20Sopenharmony_ci		 * NFC Forum Digistal Spec Table 17:
4418c2ecf20Sopenharmony_ci		 * b3 set to 0b (value b7-b6):
4428c2ecf20Sopenharmony_ci		 * - 10b: Configured for NFC-DEP Protocol
4438c2ecf20Sopenharmony_ci		 */
4448c2ecf20Sopenharmony_ci		param[0] = 0x40;
4458c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4468c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_SEL_RES, param, 1);
4478c2ecf20Sopenharmony_ci		if (r < 0)
4488c2ecf20Sopenharmony_ci			return r;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci		/* Configure NFCID1 Random uid */
4518c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4528c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_NFCID1, NULL, 0);
4538c2ecf20Sopenharmony_ci		if (r < 0)
4548c2ecf20Sopenharmony_ci			return r;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		/* Configure NFCID2_LIST */
4578c2ecf20Sopenharmony_ci		/* System Code */
4588c2ecf20Sopenharmony_ci		param[0] = 0x00;
4598c2ecf20Sopenharmony_ci		param[1] = 0x00;
4608c2ecf20Sopenharmony_ci		/* NFCID2 */
4618c2ecf20Sopenharmony_ci		param[2] = 0x01;
4628c2ecf20Sopenharmony_ci		param[3] = 0xfe;
4638c2ecf20Sopenharmony_ci		param[4] = 'S';
4648c2ecf20Sopenharmony_ci		param[5] = 'T';
4658c2ecf20Sopenharmony_ci		param[6] = 'M';
4668c2ecf20Sopenharmony_ci		param[7] = 'i';
4678c2ecf20Sopenharmony_ci		param[8] = 'c';
4688c2ecf20Sopenharmony_ci		param[9] = 'r';
4698c2ecf20Sopenharmony_ci		/* 8 byte Pad bytes used for polling respone frame */
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		/*
4728c2ecf20Sopenharmony_ci		 * Configuration byte:
4738c2ecf20Sopenharmony_ci		 * - bit 0: define the default NFCID2 entry used when the
4748c2ecf20Sopenharmony_ci		 * system code is equal to 'FFFF'
4758c2ecf20Sopenharmony_ci		 * - bit 1: use a random value for lowest 6 bytes of
4768c2ecf20Sopenharmony_ci		 * NFCID2 value
4778c2ecf20Sopenharmony_ci		 * - bit 2: ignore polling request frame if request code
4788c2ecf20Sopenharmony_ci		 * is equal to '01'
4798c2ecf20Sopenharmony_ci		 * - Other bits are RFU
4808c2ecf20Sopenharmony_ci		 */
4818c2ecf20Sopenharmony_ci		param[18] = 0x01;
4828c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4838c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_NFCID2_LIST, param,
4848c2ecf20Sopenharmony_ci				      19);
4858c2ecf20Sopenharmony_ci		if (r < 0)
4868c2ecf20Sopenharmony_ci			return r;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci		param[0] = 0x02;
4898c2ecf20Sopenharmony_ci		r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
4908c2ecf20Sopenharmony_ci				      ST21NFCA_RF_CARD_F_MODE, param, 1);
4918c2ecf20Sopenharmony_ci	}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	return r;
4948c2ecf20Sopenharmony_ci}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_cistatic void st21nfca_hci_stop_poll(struct nfc_hci_dev *hdev)
4978c2ecf20Sopenharmony_ci{
4988c2ecf20Sopenharmony_ci	nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
4998c2ecf20Sopenharmony_ci			ST21NFCA_DM_DISCONNECT, NULL, 0, NULL);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic int st21nfca_get_iso14443_3_atqa(struct nfc_hci_dev *hdev, u16 *atqa)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	int r;
5058c2ecf20Sopenharmony_ci	struct sk_buff *atqa_skb = NULL;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_14443_3_A_GATE,
5088c2ecf20Sopenharmony_ci			      ST21NFCA_RF_READER_14443_3_A_ATQA, &atqa_skb);
5098c2ecf20Sopenharmony_ci	if (r < 0)
5108c2ecf20Sopenharmony_ci		goto exit;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	if (atqa_skb->len != 2) {
5138c2ecf20Sopenharmony_ci		r = -EPROTO;
5148c2ecf20Sopenharmony_ci		goto exit;
5158c2ecf20Sopenharmony_ci	}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	*atqa = be16_to_cpu(*(__be16 *) atqa_skb->data);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ciexit:
5208c2ecf20Sopenharmony_ci	kfree_skb(atqa_skb);
5218c2ecf20Sopenharmony_ci	return r;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_cistatic int st21nfca_get_iso14443_3_sak(struct nfc_hci_dev *hdev, u8 *sak)
5258c2ecf20Sopenharmony_ci{
5268c2ecf20Sopenharmony_ci	int r;
5278c2ecf20Sopenharmony_ci	struct sk_buff *sak_skb = NULL;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_14443_3_A_GATE,
5308c2ecf20Sopenharmony_ci			      ST21NFCA_RF_READER_14443_3_A_SAK, &sak_skb);
5318c2ecf20Sopenharmony_ci	if (r < 0)
5328c2ecf20Sopenharmony_ci		goto exit;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	if (sak_skb->len != 1) {
5358c2ecf20Sopenharmony_ci		r = -EPROTO;
5368c2ecf20Sopenharmony_ci		goto exit;
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	*sak = sak_skb->data[0];
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ciexit:
5428c2ecf20Sopenharmony_ci	kfree_skb(sak_skb);
5438c2ecf20Sopenharmony_ci	return r;
5448c2ecf20Sopenharmony_ci}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_cistatic int st21nfca_get_iso14443_3_uid(struct nfc_hci_dev *hdev, u8 *uid,
5478c2ecf20Sopenharmony_ci				       int *len)
5488c2ecf20Sopenharmony_ci{
5498c2ecf20Sopenharmony_ci	int r;
5508c2ecf20Sopenharmony_ci	struct sk_buff *uid_skb = NULL;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_14443_3_A_GATE,
5538c2ecf20Sopenharmony_ci			      ST21NFCA_RF_READER_14443_3_A_UID, &uid_skb);
5548c2ecf20Sopenharmony_ci	if (r < 0)
5558c2ecf20Sopenharmony_ci		goto exit;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	if (uid_skb->len == 0 || uid_skb->len > NFC_NFCID1_MAXSIZE) {
5588c2ecf20Sopenharmony_ci		r = -EPROTO;
5598c2ecf20Sopenharmony_ci		goto exit;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	memcpy(uid, uid_skb->data, uid_skb->len);
5638c2ecf20Sopenharmony_ci	*len = uid_skb->len;
5648c2ecf20Sopenharmony_ciexit:
5658c2ecf20Sopenharmony_ci	kfree_skb(uid_skb);
5668c2ecf20Sopenharmony_ci	return r;
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_cistatic int st21nfca_get_iso15693_inventory(struct nfc_hci_dev *hdev,
5708c2ecf20Sopenharmony_ci					   struct nfc_target *target)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	int r;
5738c2ecf20Sopenharmony_ci	struct sk_buff *inventory_skb = NULL;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_ISO15693_GATE,
5768c2ecf20Sopenharmony_ci			      ST21NFCA_RF_READER_ISO15693_INVENTORY,
5778c2ecf20Sopenharmony_ci			      &inventory_skb);
5788c2ecf20Sopenharmony_ci	if (r < 0)
5798c2ecf20Sopenharmony_ci		goto exit;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	skb_pull(inventory_skb, 2);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	if (inventory_skb->len == 0 ||
5848c2ecf20Sopenharmony_ci	    inventory_skb->len > NFC_ISO15693_UID_MAXSIZE) {
5858c2ecf20Sopenharmony_ci		r = -EPROTO;
5868c2ecf20Sopenharmony_ci		goto exit;
5878c2ecf20Sopenharmony_ci	}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	memcpy(target->iso15693_uid, inventory_skb->data, inventory_skb->len);
5908c2ecf20Sopenharmony_ci	target->iso15693_dsfid	= inventory_skb->data[1];
5918c2ecf20Sopenharmony_ci	target->is_iso15693 = 1;
5928c2ecf20Sopenharmony_ciexit:
5938c2ecf20Sopenharmony_ci	kfree_skb(inventory_skb);
5948c2ecf20Sopenharmony_ci	return r;
5958c2ecf20Sopenharmony_ci}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_cistatic int st21nfca_hci_dep_link_up(struct nfc_hci_dev *hdev,
5988c2ecf20Sopenharmony_ci				    struct nfc_target *target, u8 comm_mode,
5998c2ecf20Sopenharmony_ci				    u8 *gb, size_t gb_len)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	info->dep_info.idx = target->idx;
6048c2ecf20Sopenharmony_ci	return st21nfca_im_send_atr_req(hdev, gb, gb_len);
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int st21nfca_hci_dep_link_down(struct nfc_hci_dev *hdev)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	info->state = ST21NFCA_ST_READY;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
6148c2ecf20Sopenharmony_ci				ST21NFCA_DM_DISCONNECT, NULL, 0, NULL);
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_cistatic int st21nfca_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
6188c2ecf20Sopenharmony_ci					 struct nfc_target *target)
6198c2ecf20Sopenharmony_ci{
6208c2ecf20Sopenharmony_ci	int r, len;
6218c2ecf20Sopenharmony_ci	u16 atqa;
6228c2ecf20Sopenharmony_ci	u8 sak;
6238c2ecf20Sopenharmony_ci	u8 uid[NFC_NFCID1_MAXSIZE];
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	switch (gate) {
6268c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_F_GATE:
6278c2ecf20Sopenharmony_ci		target->supported_protocols = NFC_PROTO_FELICA_MASK;
6288c2ecf20Sopenharmony_ci		break;
6298c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_14443_3_A_GATE:
6308c2ecf20Sopenharmony_ci		/* ISO14443-3 type 1 or 2 tags */
6318c2ecf20Sopenharmony_ci		r = st21nfca_get_iso14443_3_atqa(hdev, &atqa);
6328c2ecf20Sopenharmony_ci		if (r < 0)
6338c2ecf20Sopenharmony_ci			return r;
6348c2ecf20Sopenharmony_ci		if (atqa == 0x000c) {
6358c2ecf20Sopenharmony_ci			target->supported_protocols = NFC_PROTO_JEWEL_MASK;
6368c2ecf20Sopenharmony_ci			target->sens_res = 0x0c00;
6378c2ecf20Sopenharmony_ci		} else {
6388c2ecf20Sopenharmony_ci			r = st21nfca_get_iso14443_3_sak(hdev, &sak);
6398c2ecf20Sopenharmony_ci			if (r < 0)
6408c2ecf20Sopenharmony_ci				return r;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci			r = st21nfca_get_iso14443_3_uid(hdev, uid, &len);
6438c2ecf20Sopenharmony_ci			if (r < 0)
6448c2ecf20Sopenharmony_ci				return r;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci			target->supported_protocols =
6478c2ecf20Sopenharmony_ci			    nfc_hci_sak_to_protocol(sak);
6488c2ecf20Sopenharmony_ci			if (target->supported_protocols == 0xffffffff)
6498c2ecf20Sopenharmony_ci				return -EPROTO;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci			target->sens_res = atqa;
6528c2ecf20Sopenharmony_ci			target->sel_res = sak;
6538c2ecf20Sopenharmony_ci			memcpy(target->nfcid1, uid, len);
6548c2ecf20Sopenharmony_ci			target->nfcid1_len = len;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci		break;
6588c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_ISO15693_GATE:
6598c2ecf20Sopenharmony_ci		target->supported_protocols = NFC_PROTO_ISO15693_MASK;
6608c2ecf20Sopenharmony_ci		r = st21nfca_get_iso15693_inventory(hdev, target);
6618c2ecf20Sopenharmony_ci		if (r < 0)
6628c2ecf20Sopenharmony_ci			return r;
6638c2ecf20Sopenharmony_ci		break;
6648c2ecf20Sopenharmony_ci	default:
6658c2ecf20Sopenharmony_ci		return -EPROTO;
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	return 0;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
6728c2ecf20Sopenharmony_ci						u8 gate,
6738c2ecf20Sopenharmony_ci						struct nfc_target *target)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	int r;
6768c2ecf20Sopenharmony_ci	struct sk_buff *nfcid_skb = NULL;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (gate == ST21NFCA_RF_READER_F_GATE) {
6798c2ecf20Sopenharmony_ci		r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
6808c2ecf20Sopenharmony_ci				ST21NFCA_RF_READER_F_NFCID2, &nfcid_skb);
6818c2ecf20Sopenharmony_ci		if (r < 0)
6828c2ecf20Sopenharmony_ci			goto exit;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		if (nfcid_skb->len > NFC_SENSF_RES_MAXSIZE) {
6858c2ecf20Sopenharmony_ci			r = -EPROTO;
6868c2ecf20Sopenharmony_ci			goto exit;
6878c2ecf20Sopenharmony_ci		}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci		/*
6908c2ecf20Sopenharmony_ci		 * - After the recepton of polling response for type F frame
6918c2ecf20Sopenharmony_ci		 * at 212 or 424 Kbit/s, NFCID2 registry parameters will be
6928c2ecf20Sopenharmony_ci		 * updated.
6938c2ecf20Sopenharmony_ci		 * - After the reception of SEL_RES with NFCIP-1 compliant bit
6948c2ecf20Sopenharmony_ci		 * set for type A frame NFCID1 will be updated
6958c2ecf20Sopenharmony_ci		 */
6968c2ecf20Sopenharmony_ci		if (nfcid_skb->len > 0) {
6978c2ecf20Sopenharmony_ci			/* P2P in type F */
6988c2ecf20Sopenharmony_ci			memcpy(target->sensf_res, nfcid_skb->data,
6998c2ecf20Sopenharmony_ci				nfcid_skb->len);
7008c2ecf20Sopenharmony_ci			target->sensf_res_len = nfcid_skb->len;
7018c2ecf20Sopenharmony_ci			/* NFC Forum Digital Protocol Table 44 */
7028c2ecf20Sopenharmony_ci			if (target->sensf_res[0] == 0x01 &&
7038c2ecf20Sopenharmony_ci			    target->sensf_res[1] == 0xfe)
7048c2ecf20Sopenharmony_ci				target->supported_protocols =
7058c2ecf20Sopenharmony_ci							NFC_PROTO_NFC_DEP_MASK;
7068c2ecf20Sopenharmony_ci			else
7078c2ecf20Sopenharmony_ci				target->supported_protocols =
7088c2ecf20Sopenharmony_ci							NFC_PROTO_FELICA_MASK;
7098c2ecf20Sopenharmony_ci		} else {
7108c2ecf20Sopenharmony_ci			kfree_skb(nfcid_skb);
7118c2ecf20Sopenharmony_ci			nfcid_skb = NULL;
7128c2ecf20Sopenharmony_ci			/* P2P in type A */
7138c2ecf20Sopenharmony_ci			r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
7148c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_F_NFCID1,
7158c2ecf20Sopenharmony_ci					&nfcid_skb);
7168c2ecf20Sopenharmony_ci			if (r < 0)
7178c2ecf20Sopenharmony_ci				goto exit;
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci			if (nfcid_skb->len > NFC_NFCID1_MAXSIZE) {
7208c2ecf20Sopenharmony_ci				r = -EPROTO;
7218c2ecf20Sopenharmony_ci				goto exit;
7228c2ecf20Sopenharmony_ci			}
7238c2ecf20Sopenharmony_ci			memcpy(target->sensf_res, nfcid_skb->data,
7248c2ecf20Sopenharmony_ci				nfcid_skb->len);
7258c2ecf20Sopenharmony_ci			target->sensf_res_len = nfcid_skb->len;
7268c2ecf20Sopenharmony_ci			target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
7278c2ecf20Sopenharmony_ci		}
7288c2ecf20Sopenharmony_ci		target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE;
7298c2ecf20Sopenharmony_ci	}
7308c2ecf20Sopenharmony_ci	r = 1;
7318c2ecf20Sopenharmony_ciexit:
7328c2ecf20Sopenharmony_ci	kfree_skb(nfcid_skb);
7338c2ecf20Sopenharmony_ci	return r;
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_ci#define ST21NFCA_CB_TYPE_READER_ISO15693 1
7378c2ecf20Sopenharmony_cistatic void st21nfca_hci_data_exchange_cb(void *context, struct sk_buff *skb,
7388c2ecf20Sopenharmony_ci					  int err)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = context;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	switch (info->async_cb_type) {
7438c2ecf20Sopenharmony_ci	case ST21NFCA_CB_TYPE_READER_ISO15693:
7448c2ecf20Sopenharmony_ci		if (err == 0)
7458c2ecf20Sopenharmony_ci			skb_trim(skb, skb->len - 1);
7468c2ecf20Sopenharmony_ci		info->async_cb(info->async_cb_context, skb, err);
7478c2ecf20Sopenharmony_ci		break;
7488c2ecf20Sopenharmony_ci	default:
7498c2ecf20Sopenharmony_ci		if (err == 0)
7508c2ecf20Sopenharmony_ci			kfree_skb(skb);
7518c2ecf20Sopenharmony_ci		break;
7528c2ecf20Sopenharmony_ci	}
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci/*
7568c2ecf20Sopenharmony_ci * Returns:
7578c2ecf20Sopenharmony_ci * <= 0: driver handled the data exchange
7588c2ecf20Sopenharmony_ci *    1: driver doesn't especially handle, please do standard processing
7598c2ecf20Sopenharmony_ci */
7608c2ecf20Sopenharmony_cistatic int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev,
7618c2ecf20Sopenharmony_ci				      struct nfc_target *target,
7628c2ecf20Sopenharmony_ci				      struct sk_buff *skb,
7638c2ecf20Sopenharmony_ci				      data_exchange_cb_t cb, void *cb_context)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	pr_info(DRIVER_DESC ": %s for gate=%d len=%d\n", __func__,
7688c2ecf20Sopenharmony_ci		target->hci_reader_gate, skb->len);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	switch (target->hci_reader_gate) {
7718c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_F_GATE:
7728c2ecf20Sopenharmony_ci		if (target->supported_protocols == NFC_PROTO_NFC_DEP_MASK)
7738c2ecf20Sopenharmony_ci			return st21nfca_im_send_dep_req(hdev, skb);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0x1a;
7768c2ecf20Sopenharmony_ci		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
7778c2ecf20Sopenharmony_ci					      ST21NFCA_WR_XCHG_DATA, skb->data,
7788c2ecf20Sopenharmony_ci					      skb->len, cb, cb_context);
7798c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_14443_3_A_GATE:
7808c2ecf20Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0x1a;	/* CTR, see spec:10.2.2.1 */
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
7838c2ecf20Sopenharmony_ci					      ST21NFCA_WR_XCHG_DATA, skb->data,
7848c2ecf20Sopenharmony_ci					      skb->len, cb, cb_context);
7858c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_ISO15693_GATE:
7868c2ecf20Sopenharmony_ci		info->async_cb_type = ST21NFCA_CB_TYPE_READER_ISO15693;
7878c2ecf20Sopenharmony_ci		info->async_cb = cb;
7888c2ecf20Sopenharmony_ci		info->async_cb_context = cb_context;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci		*(u8 *)skb_push(skb, 1) = 0x17;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci		return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
7938c2ecf20Sopenharmony_ci					      ST21NFCA_WR_XCHG_DATA, skb->data,
7948c2ecf20Sopenharmony_ci					      skb->len,
7958c2ecf20Sopenharmony_ci					      st21nfca_hci_data_exchange_cb,
7968c2ecf20Sopenharmony_ci					      info);
7978c2ecf20Sopenharmony_ci	default:
7988c2ecf20Sopenharmony_ci		return 1;
7998c2ecf20Sopenharmony_ci	}
8008c2ecf20Sopenharmony_ci}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_cistatic int st21nfca_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	return st21nfca_tm_send_dep_res(hdev, skb);
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_cistatic int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
8088c2ecf20Sopenharmony_ci				       struct nfc_target *target)
8098c2ecf20Sopenharmony_ci{
8108c2ecf20Sopenharmony_ci	u8 fwi = 0x11;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	switch (target->hci_reader_gate) {
8138c2ecf20Sopenharmony_ci	case NFC_HCI_RF_READER_A_GATE:
8148c2ecf20Sopenharmony_ci	case NFC_HCI_RF_READER_B_GATE:
8158c2ecf20Sopenharmony_ci		/*
8168c2ecf20Sopenharmony_ci		 * PRESENCE_CHECK on those gates is available
8178c2ecf20Sopenharmony_ci		 * However, the answer to this command is taking 3 * fwi
8188c2ecf20Sopenharmony_ci		 * if the card is no present.
8198c2ecf20Sopenharmony_ci		 * Instead, we send an empty I-Frame with a very short
8208c2ecf20Sopenharmony_ci		 * configurable fwi ~604µs.
8218c2ecf20Sopenharmony_ci		 */
8228c2ecf20Sopenharmony_ci		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
8238c2ecf20Sopenharmony_ci					ST21NFCA_WR_XCHG_DATA, &fwi, 1, NULL);
8248c2ecf20Sopenharmony_ci	case ST21NFCA_RF_READER_14443_3_A_GATE:
8258c2ecf20Sopenharmony_ci		return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
8268c2ecf20Sopenharmony_ci					ST21NFCA_RF_READER_CMD_PRESENCE_CHECK,
8278c2ecf20Sopenharmony_ci					NULL, 0, NULL);
8288c2ecf20Sopenharmony_ci	default:
8298c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci}
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_cistatic void st21nfca_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
8348c2ecf20Sopenharmony_ci				struct sk_buff *skb)
8358c2ecf20Sopenharmony_ci{
8368c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
8378c2ecf20Sopenharmony_ci	u8 gate = hdev->pipes[pipe].gate;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	pr_debug("cmd: %x\n", cmd);
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	switch (cmd) {
8428c2ecf20Sopenharmony_ci	case NFC_HCI_ANY_OPEN_PIPE:
8438c2ecf20Sopenharmony_ci		if (gate != ST21NFCA_APDU_READER_GATE &&
8448c2ecf20Sopenharmony_ci			hdev->pipes[pipe].dest_host != NFC_HCI_UICC_HOST_ID)
8458c2ecf20Sopenharmony_ci			info->se_info.count_pipes++;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci		if (info->se_info.count_pipes == info->se_info.expected_pipes) {
8488c2ecf20Sopenharmony_ci			del_timer_sync(&info->se_info.se_active_timer);
8498c2ecf20Sopenharmony_ci			info->se_info.se_active = false;
8508c2ecf20Sopenharmony_ci			info->se_info.count_pipes = 0;
8518c2ecf20Sopenharmony_ci			complete(&info->se_info.req_completion);
8528c2ecf20Sopenharmony_ci		}
8538c2ecf20Sopenharmony_ci	break;
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_cistatic int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event,
8588c2ecf20Sopenharmony_ci					struct sk_buff *skb)
8598c2ecf20Sopenharmony_ci{
8608c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	pr_debug("admin event: %x\n", event);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	switch (event) {
8658c2ecf20Sopenharmony_ci	case ST21NFCA_EVT_HOT_PLUG:
8668c2ecf20Sopenharmony_ci		if (info->se_info.se_active) {
8678c2ecf20Sopenharmony_ci			if (!ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
8688c2ecf20Sopenharmony_ci				del_timer_sync(&info->se_info.se_active_timer);
8698c2ecf20Sopenharmony_ci				info->se_info.se_active = false;
8708c2ecf20Sopenharmony_ci				complete(&info->se_info.req_completion);
8718c2ecf20Sopenharmony_ci			} else {
8728c2ecf20Sopenharmony_ci				mod_timer(&info->se_info.se_active_timer,
8738c2ecf20Sopenharmony_ci					jiffies +
8748c2ecf20Sopenharmony_ci					msecs_to_jiffies(ST21NFCA_SE_TO_PIPES));
8758c2ecf20Sopenharmony_ci			}
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci	break;
8788c2ecf20Sopenharmony_ci	default:
8798c2ecf20Sopenharmony_ci		nfc_err(&hdev->ndev->dev, "Unexpected event on admin gate\n");
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci	kfree_skb(skb);
8828c2ecf20Sopenharmony_ci	return 0;
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci/*
8868c2ecf20Sopenharmony_ci * Returns:
8878c2ecf20Sopenharmony_ci * <= 0: driver handled the event, skb consumed
8888c2ecf20Sopenharmony_ci *    1: driver does not handle the event, please do standard processing
8898c2ecf20Sopenharmony_ci */
8908c2ecf20Sopenharmony_cistatic int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe,
8918c2ecf20Sopenharmony_ci				       u8 event, struct sk_buff *skb)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	u8 gate = hdev->pipes[pipe].gate;
8948c2ecf20Sopenharmony_ci	u8 host = hdev->pipes[pipe].dest_host;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	pr_debug("hci event: %d gate: %x\n", event, gate);
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	switch (gate) {
8998c2ecf20Sopenharmony_ci	case NFC_HCI_ADMIN_GATE:
9008c2ecf20Sopenharmony_ci		return st21nfca_admin_event_received(hdev, event, skb);
9018c2ecf20Sopenharmony_ci	case ST21NFCA_RF_CARD_F_GATE:
9028c2ecf20Sopenharmony_ci		return st21nfca_dep_event_received(hdev, event, skb);
9038c2ecf20Sopenharmony_ci	case ST21NFCA_CONNECTIVITY_GATE:
9048c2ecf20Sopenharmony_ci		return st21nfca_connectivity_event_received(hdev, host,
9058c2ecf20Sopenharmony_ci							event, skb);
9068c2ecf20Sopenharmony_ci	case ST21NFCA_APDU_READER_GATE:
9078c2ecf20Sopenharmony_ci		return st21nfca_apdu_reader_event_received(hdev, event, skb);
9088c2ecf20Sopenharmony_ci	case NFC_HCI_LOOPBACK_GATE:
9098c2ecf20Sopenharmony_ci		return st21nfca_hci_loopback_event_received(hdev, event, skb);
9108c2ecf20Sopenharmony_ci	default:
9118c2ecf20Sopenharmony_ci		return 1;
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_cistatic struct nfc_hci_ops st21nfca_hci_ops = {
9168c2ecf20Sopenharmony_ci	.open = st21nfca_hci_open,
9178c2ecf20Sopenharmony_ci	.close = st21nfca_hci_close,
9188c2ecf20Sopenharmony_ci	.load_session = st21nfca_hci_load_session,
9198c2ecf20Sopenharmony_ci	.hci_ready = st21nfca_hci_ready,
9208c2ecf20Sopenharmony_ci	.xmit = st21nfca_hci_xmit,
9218c2ecf20Sopenharmony_ci	.start_poll = st21nfca_hci_start_poll,
9228c2ecf20Sopenharmony_ci	.stop_poll = st21nfca_hci_stop_poll,
9238c2ecf20Sopenharmony_ci	.dep_link_up = st21nfca_hci_dep_link_up,
9248c2ecf20Sopenharmony_ci	.dep_link_down = st21nfca_hci_dep_link_down,
9258c2ecf20Sopenharmony_ci	.target_from_gate = st21nfca_hci_target_from_gate,
9268c2ecf20Sopenharmony_ci	.complete_target_discovered = st21nfca_hci_complete_target_discovered,
9278c2ecf20Sopenharmony_ci	.im_transceive = st21nfca_hci_im_transceive,
9288c2ecf20Sopenharmony_ci	.tm_send = st21nfca_hci_tm_send,
9298c2ecf20Sopenharmony_ci	.check_presence = st21nfca_hci_check_presence,
9308c2ecf20Sopenharmony_ci	.event_received = st21nfca_hci_event_received,
9318c2ecf20Sopenharmony_ci	.cmd_received = st21nfca_hci_cmd_received,
9328c2ecf20Sopenharmony_ci	.discover_se = st21nfca_hci_discover_se,
9338c2ecf20Sopenharmony_ci	.enable_se = st21nfca_hci_enable_se,
9348c2ecf20Sopenharmony_ci	.disable_se = st21nfca_hci_disable_se,
9358c2ecf20Sopenharmony_ci	.se_io = st21nfca_hci_se_io,
9368c2ecf20Sopenharmony_ci};
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ciint st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
9398c2ecf20Sopenharmony_ci		       char *llc_name, int phy_headroom, int phy_tailroom,
9408c2ecf20Sopenharmony_ci		       int phy_payload, struct nfc_hci_dev **hdev,
9418c2ecf20Sopenharmony_ci			   struct st21nfca_se_status *se_status)
9428c2ecf20Sopenharmony_ci{
9438c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info;
9448c2ecf20Sopenharmony_ci	int r = 0;
9458c2ecf20Sopenharmony_ci	int dev_num;
9468c2ecf20Sopenharmony_ci	u32 protocols;
9478c2ecf20Sopenharmony_ci	struct nfc_hci_init_data init_data;
9488c2ecf20Sopenharmony_ci	unsigned long quirks = 0;
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	info = kzalloc(sizeof(struct st21nfca_hci_info), GFP_KERNEL);
9518c2ecf20Sopenharmony_ci	if (!info)
9528c2ecf20Sopenharmony_ci		return -ENOMEM;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	info->phy_ops = phy_ops;
9558c2ecf20Sopenharmony_ci	info->phy_id = phy_id;
9568c2ecf20Sopenharmony_ci	info->state = ST21NFCA_ST_COLD;
9578c2ecf20Sopenharmony_ci	mutex_init(&info->info_lock);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	init_data.gate_count = ARRAY_SIZE(st21nfca_gates);
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	memcpy(init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	/*
9648c2ecf20Sopenharmony_ci	 * Session id must include the driver name + i2c bus addr
9658c2ecf20Sopenharmony_ci	 * persistent info to discriminate 2 identical chips
9668c2ecf20Sopenharmony_ci	 */
9678c2ecf20Sopenharmony_ci	dev_num = find_first_zero_bit(dev_mask, ST21NFCA_NUM_DEVICES);
9688c2ecf20Sopenharmony_ci	if (dev_num >= ST21NFCA_NUM_DEVICES) {
9698c2ecf20Sopenharmony_ci		r = -ENODEV;
9708c2ecf20Sopenharmony_ci		goto err_alloc_hdev;
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	set_bit(dev_num, dev_mask);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	scnprintf(init_data.session_id, sizeof(init_data.session_id), "%s%2x",
9768c2ecf20Sopenharmony_ci		  "ST21AH", dev_num);
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci	protocols = NFC_PROTO_JEWEL_MASK |
9798c2ecf20Sopenharmony_ci	    NFC_PROTO_MIFARE_MASK |
9808c2ecf20Sopenharmony_ci	    NFC_PROTO_FELICA_MASK |
9818c2ecf20Sopenharmony_ci	    NFC_PROTO_ISO14443_MASK |
9828c2ecf20Sopenharmony_ci	    NFC_PROTO_ISO14443_B_MASK |
9838c2ecf20Sopenharmony_ci	    NFC_PROTO_ISO15693_MASK |
9848c2ecf20Sopenharmony_ci	    NFC_PROTO_NFC_DEP_MASK;
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci	set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci	info->hdev =
9898c2ecf20Sopenharmony_ci	    nfc_hci_allocate_device(&st21nfca_hci_ops, &init_data, quirks,
9908c2ecf20Sopenharmony_ci				    protocols, llc_name,
9918c2ecf20Sopenharmony_ci				    phy_headroom + ST21NFCA_CMDS_HEADROOM,
9928c2ecf20Sopenharmony_ci				    phy_tailroom, phy_payload);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci	if (!info->hdev) {
9958c2ecf20Sopenharmony_ci		pr_err("Cannot allocate nfc hdev.\n");
9968c2ecf20Sopenharmony_ci		r = -ENOMEM;
9978c2ecf20Sopenharmony_ci		goto err_alloc_hdev;
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	info->se_status = se_status;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	nfc_hci_set_clientdata(info->hdev, info);
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	r = nfc_hci_register_device(info->hdev);
10058c2ecf20Sopenharmony_ci	if (r)
10068c2ecf20Sopenharmony_ci		goto err_regdev;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	*hdev = info->hdev;
10098c2ecf20Sopenharmony_ci	st21nfca_dep_init(info->hdev);
10108c2ecf20Sopenharmony_ci	st21nfca_se_init(info->hdev);
10118c2ecf20Sopenharmony_ci	st21nfca_vendor_cmds_init(info->hdev);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	return 0;
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_cierr_regdev:
10168c2ecf20Sopenharmony_ci	nfc_hci_free_device(info->hdev);
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cierr_alloc_hdev:
10198c2ecf20Sopenharmony_ci	kfree(info);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	return r;
10228c2ecf20Sopenharmony_ci}
10238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(st21nfca_hci_probe);
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_civoid st21nfca_hci_remove(struct nfc_hci_dev *hdev)
10268c2ecf20Sopenharmony_ci{
10278c2ecf20Sopenharmony_ci	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	st21nfca_dep_deinit(hdev);
10308c2ecf20Sopenharmony_ci	st21nfca_se_deinit(hdev);
10318c2ecf20Sopenharmony_ci	nfc_hci_unregister_device(hdev);
10328c2ecf20Sopenharmony_ci	nfc_hci_free_device(hdev);
10338c2ecf20Sopenharmony_ci	kfree(info);
10348c2ecf20Sopenharmony_ci}
10358c2ecf20Sopenharmony_ciEXPORT_SYMBOL(st21nfca_hci_remove);
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
10388c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
1039