18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * NFC Digital Protocol stack
48c2ecf20Sopenharmony_ci * Copyright (c) 2013, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "digital: %s: " fmt, __func__
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "digital.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#define DIGITAL_PROTO_NFCA_RF_TECH \
148c2ecf20Sopenharmony_ci	(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | \
158c2ecf20Sopenharmony_ci	NFC_PROTO_NFC_DEP_MASK | NFC_PROTO_ISO14443_MASK)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define DIGITAL_PROTO_NFCB_RF_TECH	NFC_PROTO_ISO14443_B_MASK
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define DIGITAL_PROTO_NFCF_RF_TECH \
208c2ecf20Sopenharmony_ci	(NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK)
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define DIGITAL_PROTO_ISO15693_RF_TECH	NFC_PROTO_ISO15693_MASK
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/* Delay between each poll frame (ms) */
258c2ecf20Sopenharmony_ci#define DIGITAL_POLL_INTERVAL 10
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistruct digital_cmd {
288c2ecf20Sopenharmony_ci	struct list_head queue;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	u8 type;
318c2ecf20Sopenharmony_ci	u8 pending;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	u16 timeout;
348c2ecf20Sopenharmony_ci	struct sk_buff *req;
358c2ecf20Sopenharmony_ci	struct sk_buff *resp;
368c2ecf20Sopenharmony_ci	struct digital_tg_mdaa_params *mdaa_params;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	nfc_digital_cmd_complete_t cmd_cb;
398c2ecf20Sopenharmony_ci	void *cb_context;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistruct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
438c2ecf20Sopenharmony_ci				  unsigned int len)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	struct sk_buff *skb;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	skb = alloc_skb(len + ddev->tx_headroom + ddev->tx_tailroom,
488c2ecf20Sopenharmony_ci			GFP_KERNEL);
498c2ecf20Sopenharmony_ci	if (skb)
508c2ecf20Sopenharmony_ci		skb_reserve(skb, ddev->tx_headroom);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return skb;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_civoid digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
568c2ecf20Sopenharmony_ci			 u8 bitwise_inv, u8 msb_first)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	u16 crc;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	crc = crc_func(init, skb->data, skb->len);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	if (bitwise_inv)
638c2ecf20Sopenharmony_ci		crc = ~crc;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	if (msb_first)
668c2ecf20Sopenharmony_ci		crc = __fswab16(crc);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	skb_put_u8(skb, crc & 0xFF);
698c2ecf20Sopenharmony_ci	skb_put_u8(skb, (crc >> 8) & 0xFF);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciint digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
738c2ecf20Sopenharmony_ci			  u16 crc_init, u8 bitwise_inv, u8 msb_first)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	int rc;
768c2ecf20Sopenharmony_ci	u16 crc;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (skb->len <= 2)
798c2ecf20Sopenharmony_ci		return -EIO;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	crc = crc_func(crc_init, skb->data, skb->len - 2);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	if (bitwise_inv)
848c2ecf20Sopenharmony_ci		crc = ~crc;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (msb_first)
878c2ecf20Sopenharmony_ci		crc = __swab16(crc);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	rc = (skb->data[skb->len - 2] - (crc & 0xFF)) +
908c2ecf20Sopenharmony_ci	     (skb->data[skb->len - 1] - ((crc >> 8) & 0xFF));
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (rc)
938c2ecf20Sopenharmony_ci		return -EIO;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	skb_trim(skb, skb->len - 2);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	ddev->ops->switch_rf(ddev, on);
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic inline void digital_abort_cmd(struct nfc_digital_dev *ddev)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	ddev->ops->abort_cmd(ddev);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic void digital_wq_cmd_complete(struct work_struct *work)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct digital_cmd *cmd;
1138c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = container_of(work,
1148c2ecf20Sopenharmony_ci						    struct nfc_digital_dev,
1158c2ecf20Sopenharmony_ci						    cmd_complete_work);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	mutex_lock(&ddev->cmd_lock);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
1208c2ecf20Sopenharmony_ci				       queue);
1218c2ecf20Sopenharmony_ci	if (!cmd) {
1228c2ecf20Sopenharmony_ci		mutex_unlock(&ddev->cmd_lock);
1238c2ecf20Sopenharmony_ci		return;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	list_del(&cmd->queue);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->cmd_lock);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!IS_ERR(cmd->resp))
1318c2ecf20Sopenharmony_ci		print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1,
1328c2ecf20Sopenharmony_ci				     cmd->resp->data, cmd->resp->len, false);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	cmd->cmd_cb(ddev, cmd->cb_context, cmd->resp);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	kfree(cmd->mdaa_params);
1378c2ecf20Sopenharmony_ci	kfree(cmd);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	schedule_work(&ddev->cmd_work);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void digital_send_cmd_complete(struct nfc_digital_dev *ddev,
1438c2ecf20Sopenharmony_ci				      void *arg, struct sk_buff *resp)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct digital_cmd *cmd = arg;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	cmd->resp = resp;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	schedule_work(&ddev->cmd_complete_work);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void digital_wq_cmd(struct work_struct *work)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	int rc;
1558c2ecf20Sopenharmony_ci	struct digital_cmd *cmd;
1568c2ecf20Sopenharmony_ci	struct digital_tg_mdaa_params *params;
1578c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = container_of(work,
1588c2ecf20Sopenharmony_ci						    struct nfc_digital_dev,
1598c2ecf20Sopenharmony_ci						    cmd_work);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	mutex_lock(&ddev->cmd_lock);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
1648c2ecf20Sopenharmony_ci				       queue);
1658c2ecf20Sopenharmony_ci	if (!cmd || cmd->pending) {
1668c2ecf20Sopenharmony_ci		mutex_unlock(&ddev->cmd_lock);
1678c2ecf20Sopenharmony_ci		return;
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	cmd->pending = 1;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->cmd_lock);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	if (cmd->req)
1758c2ecf20Sopenharmony_ci		print_hex_dump_debug("DIGITAL TX: ", DUMP_PREFIX_NONE, 16, 1,
1768c2ecf20Sopenharmony_ci				     cmd->req->data, cmd->req->len, false);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	switch (cmd->type) {
1798c2ecf20Sopenharmony_ci	case DIGITAL_CMD_IN_SEND:
1808c2ecf20Sopenharmony_ci		rc = ddev->ops->in_send_cmd(ddev, cmd->req, cmd->timeout,
1818c2ecf20Sopenharmony_ci					    digital_send_cmd_complete, cmd);
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	case DIGITAL_CMD_TG_SEND:
1858c2ecf20Sopenharmony_ci		rc = ddev->ops->tg_send_cmd(ddev, cmd->req, cmd->timeout,
1868c2ecf20Sopenharmony_ci					    digital_send_cmd_complete, cmd);
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	case DIGITAL_CMD_TG_LISTEN:
1908c2ecf20Sopenharmony_ci		rc = ddev->ops->tg_listen(ddev, cmd->timeout,
1918c2ecf20Sopenharmony_ci					  digital_send_cmd_complete, cmd);
1928c2ecf20Sopenharmony_ci		break;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	case DIGITAL_CMD_TG_LISTEN_MDAA:
1958c2ecf20Sopenharmony_ci		params = cmd->mdaa_params;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		rc = ddev->ops->tg_listen_mdaa(ddev, params, cmd->timeout,
1988c2ecf20Sopenharmony_ci					       digital_send_cmd_complete, cmd);
1998c2ecf20Sopenharmony_ci		break;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	case DIGITAL_CMD_TG_LISTEN_MD:
2028c2ecf20Sopenharmony_ci		rc = ddev->ops->tg_listen_md(ddev, cmd->timeout,
2038c2ecf20Sopenharmony_ci					       digital_send_cmd_complete, cmd);
2048c2ecf20Sopenharmony_ci		break;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	default:
2078c2ecf20Sopenharmony_ci		pr_err("Unknown cmd type %d\n", cmd->type);
2088c2ecf20Sopenharmony_ci		return;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (!rc)
2128c2ecf20Sopenharmony_ci		return;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	pr_err("in_send_command returned err %d\n", rc);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	mutex_lock(&ddev->cmd_lock);
2178c2ecf20Sopenharmony_ci	list_del(&cmd->queue);
2188c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->cmd_lock);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	kfree_skb(cmd->req);
2218c2ecf20Sopenharmony_ci	kfree(cmd->mdaa_params);
2228c2ecf20Sopenharmony_ci	kfree(cmd);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	schedule_work(&ddev->cmd_work);
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ciint digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type,
2288c2ecf20Sopenharmony_ci		     struct sk_buff *skb, struct digital_tg_mdaa_params *params,
2298c2ecf20Sopenharmony_ci		     u16 timeout, nfc_digital_cmd_complete_t cmd_cb,
2308c2ecf20Sopenharmony_ci		     void *cb_context)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	struct digital_cmd *cmd;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
2358c2ecf20Sopenharmony_ci	if (!cmd)
2368c2ecf20Sopenharmony_ci		return -ENOMEM;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	cmd->type = cmd_type;
2398c2ecf20Sopenharmony_ci	cmd->timeout = timeout;
2408c2ecf20Sopenharmony_ci	cmd->req = skb;
2418c2ecf20Sopenharmony_ci	cmd->mdaa_params = params;
2428c2ecf20Sopenharmony_ci	cmd->cmd_cb = cmd_cb;
2438c2ecf20Sopenharmony_ci	cmd->cb_context = cb_context;
2448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cmd->queue);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	mutex_lock(&ddev->cmd_lock);
2478c2ecf20Sopenharmony_ci	list_add_tail(&cmd->queue, &ddev->cmd_queue);
2488c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->cmd_lock);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	schedule_work(&ddev->cmd_work);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return 0;
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ciint digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	int rc;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	rc = ddev->ops->in_configure_hw(ddev, type, param);
2608c2ecf20Sopenharmony_ci	if (rc)
2618c2ecf20Sopenharmony_ci		pr_err("in_configure_hw failed: %d\n", rc);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return rc;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciint digital_tg_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	int rc;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	rc = ddev->ops->tg_configure_hw(ddev, type, param);
2718c2ecf20Sopenharmony_ci	if (rc)
2728c2ecf20Sopenharmony_ci		pr_err("tg_configure_hw failed: %d\n", rc);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return rc;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct digital_tg_mdaa_params *params;
2808c2ecf20Sopenharmony_ci	int rc;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	params = kzalloc(sizeof(*params), GFP_KERNEL);
2838c2ecf20Sopenharmony_ci	if (!params)
2848c2ecf20Sopenharmony_ci		return -ENOMEM;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	params->sens_res = DIGITAL_SENS_RES_NFC_DEP;
2878c2ecf20Sopenharmony_ci	get_random_bytes(params->nfcid1, sizeof(params->nfcid1));
2888c2ecf20Sopenharmony_ci	params->sel_res = DIGITAL_SEL_RES_NFC_DEP;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	params->nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1;
2918c2ecf20Sopenharmony_ci	params->nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2;
2928c2ecf20Sopenharmony_ci	get_random_bytes(params->nfcid2 + 2, NFC_NFCID2_MAXSIZE - 2);
2938c2ecf20Sopenharmony_ci	params->sc = DIGITAL_SENSF_FELICA_SC;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	rc = digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MDAA, NULL, params,
2968c2ecf20Sopenharmony_ci			      500, digital_tg_recv_atr_req, NULL);
2978c2ecf20Sopenharmony_ci	if (rc)
2988c2ecf20Sopenharmony_ci		kfree(params);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	return rc;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500,
3068c2ecf20Sopenharmony_ci				digital_tg_recv_md_req, NULL);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ciint digital_target_found(struct nfc_digital_dev *ddev,
3108c2ecf20Sopenharmony_ci			 struct nfc_target *target, u8 protocol)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	int rc;
3138c2ecf20Sopenharmony_ci	u8 framing;
3148c2ecf20Sopenharmony_ci	u8 rf_tech;
3158c2ecf20Sopenharmony_ci	u8 poll_tech_count;
3168c2ecf20Sopenharmony_ci	int (*check_crc)(struct sk_buff *skb);
3178c2ecf20Sopenharmony_ci	void (*add_crc)(struct sk_buff *skb);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	rf_tech = ddev->poll_techs[ddev->poll_tech_index].rf_tech;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	switch (protocol) {
3228c2ecf20Sopenharmony_ci	case NFC_PROTO_JEWEL:
3238c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_NFCA_T1T;
3248c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_b;
3258c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_b;
3268c2ecf20Sopenharmony_ci		break;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	case NFC_PROTO_MIFARE:
3298c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_NFCA_T2T;
3308c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_a;
3318c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_a;
3328c2ecf20Sopenharmony_ci		break;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	case NFC_PROTO_FELICA:
3358c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_NFCF_T3T;
3368c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_f;
3378c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_f;
3388c2ecf20Sopenharmony_ci		break;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	case NFC_PROTO_NFC_DEP:
3418c2ecf20Sopenharmony_ci		if (rf_tech == NFC_DIGITAL_RF_TECH_106A) {
3428c2ecf20Sopenharmony_ci			framing = NFC_DIGITAL_FRAMING_NFCA_NFC_DEP;
3438c2ecf20Sopenharmony_ci			check_crc = digital_skb_check_crc_a;
3448c2ecf20Sopenharmony_ci			add_crc = digital_skb_add_crc_a;
3458c2ecf20Sopenharmony_ci		} else {
3468c2ecf20Sopenharmony_ci			framing = NFC_DIGITAL_FRAMING_NFCF_NFC_DEP;
3478c2ecf20Sopenharmony_ci			check_crc = digital_skb_check_crc_f;
3488c2ecf20Sopenharmony_ci			add_crc = digital_skb_add_crc_f;
3498c2ecf20Sopenharmony_ci		}
3508c2ecf20Sopenharmony_ci		break;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	case NFC_PROTO_ISO15693:
3538c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_ISO15693_T5T;
3548c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_b;
3558c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_b;
3568c2ecf20Sopenharmony_ci		break;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	case NFC_PROTO_ISO14443:
3598c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_NFCA_T4T;
3608c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_a;
3618c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_a;
3628c2ecf20Sopenharmony_ci		break;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	case NFC_PROTO_ISO14443_B:
3658c2ecf20Sopenharmony_ci		framing = NFC_DIGITAL_FRAMING_NFCB_T4T;
3668c2ecf20Sopenharmony_ci		check_crc = digital_skb_check_crc_b;
3678c2ecf20Sopenharmony_ci		add_crc = digital_skb_add_crc_b;
3688c2ecf20Sopenharmony_ci		break;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	default:
3718c2ecf20Sopenharmony_ci		pr_err("Invalid protocol %d\n", protocol);
3728c2ecf20Sopenharmony_ci		return -EINVAL;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	ddev->curr_rf_tech = rf_tech;
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
3808c2ecf20Sopenharmony_ci		ddev->skb_add_crc = digital_skb_add_crc_none;
3818c2ecf20Sopenharmony_ci		ddev->skb_check_crc = digital_skb_check_crc_none;
3828c2ecf20Sopenharmony_ci	} else {
3838c2ecf20Sopenharmony_ci		ddev->skb_add_crc = add_crc;
3848c2ecf20Sopenharmony_ci		ddev->skb_check_crc = check_crc;
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, framing);
3888c2ecf20Sopenharmony_ci	if (rc)
3898c2ecf20Sopenharmony_ci		return rc;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	target->supported_protocols = (1 << protocol);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	poll_tech_count = ddev->poll_tech_count;
3948c2ecf20Sopenharmony_ci	ddev->poll_tech_count = 0;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	rc = nfc_targets_found(ddev->nfc_dev, target, 1);
3978c2ecf20Sopenharmony_ci	if (rc) {
3988c2ecf20Sopenharmony_ci		ddev->poll_tech_count = poll_tech_count;
3998c2ecf20Sopenharmony_ci		return rc;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	return 0;
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_civoid digital_poll_next_tech(struct nfc_digital_dev *ddev)
4068c2ecf20Sopenharmony_ci{
4078c2ecf20Sopenharmony_ci	u8 rand_mod;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	digital_switch_rf(ddev, 0);
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	mutex_lock(&ddev->poll_lock);
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	if (!ddev->poll_tech_count) {
4148c2ecf20Sopenharmony_ci		mutex_unlock(&ddev->poll_lock);
4158c2ecf20Sopenharmony_ci		return;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	get_random_bytes(&rand_mod, sizeof(rand_mod));
4198c2ecf20Sopenharmony_ci	ddev->poll_tech_index = rand_mod % ddev->poll_tech_count;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->poll_lock);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	schedule_delayed_work(&ddev->poll_work,
4248c2ecf20Sopenharmony_ci			      msecs_to_jiffies(DIGITAL_POLL_INTERVAL));
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void digital_wq_poll(struct work_struct *work)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	int rc;
4308c2ecf20Sopenharmony_ci	struct digital_poll_tech *poll_tech;
4318c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = container_of(work,
4328c2ecf20Sopenharmony_ci						    struct nfc_digital_dev,
4338c2ecf20Sopenharmony_ci						    poll_work.work);
4348c2ecf20Sopenharmony_ci	mutex_lock(&ddev->poll_lock);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (!ddev->poll_tech_count) {
4378c2ecf20Sopenharmony_ci		mutex_unlock(&ddev->poll_lock);
4388c2ecf20Sopenharmony_ci		return;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	poll_tech = &ddev->poll_techs[ddev->poll_tech_index];
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->poll_lock);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	rc = poll_tech->poll_func(ddev, poll_tech->rf_tech);
4468c2ecf20Sopenharmony_ci	if (rc)
4478c2ecf20Sopenharmony_ci		digital_poll_next_tech(ddev);
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void digital_add_poll_tech(struct nfc_digital_dev *ddev, u8 rf_tech,
4518c2ecf20Sopenharmony_ci				  digital_poll_t poll_func)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct digital_poll_tech *poll_tech;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	if (ddev->poll_tech_count >= NFC_DIGITAL_POLL_MODE_COUNT_MAX)
4568c2ecf20Sopenharmony_ci		return;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	poll_tech = &ddev->poll_techs[ddev->poll_tech_count++];
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	poll_tech->rf_tech = rf_tech;
4618c2ecf20Sopenharmony_ci	poll_tech->poll_func = poll_func;
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci/**
4658c2ecf20Sopenharmony_ci * start_poll operation
4668c2ecf20Sopenharmony_ci *
4678c2ecf20Sopenharmony_ci * For every supported protocol, the corresponding polling function is added
4688c2ecf20Sopenharmony_ci * to the table of polling technologies (ddev->poll_techs[]) using
4698c2ecf20Sopenharmony_ci * digital_add_poll_tech().
4708c2ecf20Sopenharmony_ci * When a polling function fails (by timeout or protocol error) the next one is
4718c2ecf20Sopenharmony_ci * schedule by digital_poll_next_tech() on the poll workqueue (ddev->poll_work).
4728c2ecf20Sopenharmony_ci */
4738c2ecf20Sopenharmony_cistatic int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
4748c2ecf20Sopenharmony_ci			      __u32 tm_protocols)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
4778c2ecf20Sopenharmony_ci	u32 matching_im_protocols, matching_tm_protocols;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	pr_debug("protocols: im 0x%x, tm 0x%x, supported 0x%x\n", im_protocols,
4808c2ecf20Sopenharmony_ci		 tm_protocols, ddev->protocols);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	matching_im_protocols = ddev->protocols & im_protocols;
4838c2ecf20Sopenharmony_ci	matching_tm_protocols = ddev->protocols & tm_protocols;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	if (!matching_im_protocols && !matching_tm_protocols) {
4868c2ecf20Sopenharmony_ci		pr_err("Unknown protocol\n");
4878c2ecf20Sopenharmony_ci		return -EINVAL;
4888c2ecf20Sopenharmony_ci	}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	if (ddev->poll_tech_count) {
4918c2ecf20Sopenharmony_ci		pr_err("Already polling\n");
4928c2ecf20Sopenharmony_ci		return -EBUSY;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	if (ddev->curr_protocol) {
4968c2ecf20Sopenharmony_ci		pr_err("A target is already active\n");
4978c2ecf20Sopenharmony_ci		return -EBUSY;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	ddev->poll_tech_count = 0;
5018c2ecf20Sopenharmony_ci	ddev->poll_tech_index = 0;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (matching_im_protocols & DIGITAL_PROTO_NFCA_RF_TECH)
5048c2ecf20Sopenharmony_ci		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
5058c2ecf20Sopenharmony_ci				      digital_in_send_sens_req);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (matching_im_protocols & DIGITAL_PROTO_NFCB_RF_TECH)
5088c2ecf20Sopenharmony_ci		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106B,
5098c2ecf20Sopenharmony_ci				      digital_in_send_sensb_req);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (matching_im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) {
5128c2ecf20Sopenharmony_ci		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
5138c2ecf20Sopenharmony_ci				      digital_in_send_sensf_req);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
5168c2ecf20Sopenharmony_ci				      digital_in_send_sensf_req);
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (matching_im_protocols & DIGITAL_PROTO_ISO15693_RF_TECH)
5208c2ecf20Sopenharmony_ci		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_ISO15693,
5218c2ecf20Sopenharmony_ci				      digital_in_send_iso15693_inv_req);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	if (matching_tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
5248c2ecf20Sopenharmony_ci		if (ddev->ops->tg_listen_mdaa) {
5258c2ecf20Sopenharmony_ci			digital_add_poll_tech(ddev, 0,
5268c2ecf20Sopenharmony_ci					      digital_tg_listen_mdaa);
5278c2ecf20Sopenharmony_ci		} else if (ddev->ops->tg_listen_md) {
5288c2ecf20Sopenharmony_ci			digital_add_poll_tech(ddev, 0,
5298c2ecf20Sopenharmony_ci					      digital_tg_listen_md);
5308c2ecf20Sopenharmony_ci		} else {
5318c2ecf20Sopenharmony_ci			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
5328c2ecf20Sopenharmony_ci					      digital_tg_listen_nfca);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
5358c2ecf20Sopenharmony_ci					      digital_tg_listen_nfcf);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
5388c2ecf20Sopenharmony_ci					      digital_tg_listen_nfcf);
5398c2ecf20Sopenharmony_ci		}
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	if (!ddev->poll_tech_count) {
5438c2ecf20Sopenharmony_ci		pr_err("Unsupported protocols: im=0x%x, tm=0x%x\n",
5448c2ecf20Sopenharmony_ci		       matching_im_protocols, matching_tm_protocols);
5458c2ecf20Sopenharmony_ci		return -EINVAL;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	schedule_delayed_work(&ddev->poll_work, 0);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cistatic void digital_stop_poll(struct nfc_dev *nfc_dev)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	mutex_lock(&ddev->poll_lock);
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	if (!ddev->poll_tech_count) {
5608c2ecf20Sopenharmony_ci		pr_err("Polling operation was not running\n");
5618c2ecf20Sopenharmony_ci		mutex_unlock(&ddev->poll_lock);
5628c2ecf20Sopenharmony_ci		return;
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	ddev->poll_tech_count = 0;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->poll_lock);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&ddev->poll_work);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	digital_abort_cmd(ddev);
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int digital_dev_up(struct nfc_dev *nfc_dev)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	digital_switch_rf(ddev, 1);
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	return 0;
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic int digital_dev_down(struct nfc_dev *nfc_dev)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	digital_switch_rf(ddev, 0);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return 0;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic int digital_dep_link_up(struct nfc_dev *nfc_dev,
5938c2ecf20Sopenharmony_ci			       struct nfc_target *target,
5948c2ecf20Sopenharmony_ci			       __u8 comm_mode, __u8 *gb, size_t gb_len)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
5978c2ecf20Sopenharmony_ci	int rc;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	rc = digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (!rc)
6028c2ecf20Sopenharmony_ci		ddev->curr_protocol = NFC_PROTO_NFC_DEP;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	return rc;
6058c2ecf20Sopenharmony_ci}
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_cistatic int digital_dep_link_down(struct nfc_dev *nfc_dev)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	digital_abort_cmd(ddev);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	ddev->curr_protocol = 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return 0;
6168c2ecf20Sopenharmony_ci}
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_cistatic int digital_activate_target(struct nfc_dev *nfc_dev,
6198c2ecf20Sopenharmony_ci				   struct nfc_target *target, __u32 protocol)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (ddev->poll_tech_count) {
6248c2ecf20Sopenharmony_ci		pr_err("Can't activate a target while polling\n");
6258c2ecf20Sopenharmony_ci		return -EBUSY;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	if (ddev->curr_protocol) {
6298c2ecf20Sopenharmony_ci		pr_err("A target is already active\n");
6308c2ecf20Sopenharmony_ci		return -EBUSY;
6318c2ecf20Sopenharmony_ci	}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	ddev->curr_protocol = protocol;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic void digital_deactivate_target(struct nfc_dev *nfc_dev,
6398c2ecf20Sopenharmony_ci				      struct nfc_target *target,
6408c2ecf20Sopenharmony_ci				      u8 mode)
6418c2ecf20Sopenharmony_ci{
6428c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	if (!ddev->curr_protocol) {
6458c2ecf20Sopenharmony_ci		pr_err("No active target\n");
6468c2ecf20Sopenharmony_ci		return;
6478c2ecf20Sopenharmony_ci	}
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	digital_abort_cmd(ddev);
6508c2ecf20Sopenharmony_ci	ddev->curr_protocol = 0;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(dev);
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	return digital_tg_send_dep_res(ddev, skb);
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
6618c2ecf20Sopenharmony_ci				     struct sk_buff *resp)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct digital_data_exch *data_exch = arg;
6648c2ecf20Sopenharmony_ci	int rc;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (IS_ERR(resp)) {
6678c2ecf20Sopenharmony_ci		rc = PTR_ERR(resp);
6688c2ecf20Sopenharmony_ci		resp = NULL;
6698c2ecf20Sopenharmony_ci		goto done;
6708c2ecf20Sopenharmony_ci	}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (ddev->curr_protocol == NFC_PROTO_MIFARE) {
6738c2ecf20Sopenharmony_ci		rc = digital_in_recv_mifare_res(resp);
6748c2ecf20Sopenharmony_ci		/* crc check is done in digital_in_recv_mifare_res() */
6758c2ecf20Sopenharmony_ci		goto done;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
6798c2ecf20Sopenharmony_ci	    (ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
6808c2ecf20Sopenharmony_ci		rc = digital_in_iso_dep_pull_sod(ddev, resp);
6818c2ecf20Sopenharmony_ci		if (rc)
6828c2ecf20Sopenharmony_ci			goto done;
6838c2ecf20Sopenharmony_ci	}
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	rc = ddev->skb_check_crc(resp);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cidone:
6888c2ecf20Sopenharmony_ci	if (rc) {
6898c2ecf20Sopenharmony_ci		kfree_skb(resp);
6908c2ecf20Sopenharmony_ci		resp = NULL;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	data_exch->cb(data_exch->cb_context, resp, rc);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	kfree(data_exch);
6968c2ecf20Sopenharmony_ci}
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_cistatic int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
6998c2ecf20Sopenharmony_ci			   struct sk_buff *skb, data_exchange_cb_t cb,
7008c2ecf20Sopenharmony_ci			   void *cb_context)
7018c2ecf20Sopenharmony_ci{
7028c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
7038c2ecf20Sopenharmony_ci	struct digital_data_exch *data_exch;
7048c2ecf20Sopenharmony_ci	int rc;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	data_exch = kzalloc(sizeof(*data_exch), GFP_KERNEL);
7078c2ecf20Sopenharmony_ci	if (!data_exch)
7088c2ecf20Sopenharmony_ci		return -ENOMEM;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	data_exch->cb = cb;
7118c2ecf20Sopenharmony_ci	data_exch->cb_context = cb_context;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) {
7148c2ecf20Sopenharmony_ci		rc = digital_in_send_dep_req(ddev, target, skb, data_exch);
7158c2ecf20Sopenharmony_ci		goto exit;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
7198c2ecf20Sopenharmony_ci	    (ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
7208c2ecf20Sopenharmony_ci		rc = digital_in_iso_dep_push_sod(ddev, skb);
7218c2ecf20Sopenharmony_ci		if (rc)
7228c2ecf20Sopenharmony_ci			goto exit;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	ddev->skb_add_crc(skb);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	rc = digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete,
7288c2ecf20Sopenharmony_ci				 data_exch);
7298c2ecf20Sopenharmony_ci
7308c2ecf20Sopenharmony_ciexit:
7318c2ecf20Sopenharmony_ci	if (rc)
7328c2ecf20Sopenharmony_ci		kfree(data_exch);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	return rc;
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_cistatic struct nfc_ops digital_nfc_ops = {
7388c2ecf20Sopenharmony_ci	.dev_up = digital_dev_up,
7398c2ecf20Sopenharmony_ci	.dev_down = digital_dev_down,
7408c2ecf20Sopenharmony_ci	.start_poll = digital_start_poll,
7418c2ecf20Sopenharmony_ci	.stop_poll = digital_stop_poll,
7428c2ecf20Sopenharmony_ci	.dep_link_up = digital_dep_link_up,
7438c2ecf20Sopenharmony_ci	.dep_link_down = digital_dep_link_down,
7448c2ecf20Sopenharmony_ci	.activate_target = digital_activate_target,
7458c2ecf20Sopenharmony_ci	.deactivate_target = digital_deactivate_target,
7468c2ecf20Sopenharmony_ci	.tm_send = digital_tg_send,
7478c2ecf20Sopenharmony_ci	.im_transceive = digital_in_send,
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistruct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
7518c2ecf20Sopenharmony_ci					    __u32 supported_protocols,
7528c2ecf20Sopenharmony_ci					    __u32 driver_capabilities,
7538c2ecf20Sopenharmony_ci					    int tx_headroom, int tx_tailroom)
7548c2ecf20Sopenharmony_ci{
7558c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev;
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen ||
7588c2ecf20Sopenharmony_ci	    !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd ||
7598c2ecf20Sopenharmony_ci	    !ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech))
7608c2ecf20Sopenharmony_ci		return NULL;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
7638c2ecf20Sopenharmony_ci	if (!ddev)
7648c2ecf20Sopenharmony_ci		return NULL;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	ddev->driver_capabilities = driver_capabilities;
7678c2ecf20Sopenharmony_ci	ddev->ops = ops;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	mutex_init(&ddev->cmd_lock);
7708c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&ddev->cmd_queue);
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	INIT_WORK(&ddev->cmd_work, digital_wq_cmd);
7738c2ecf20Sopenharmony_ci	INIT_WORK(&ddev->cmd_complete_work, digital_wq_cmd_complete);
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	mutex_init(&ddev->poll_lock);
7768c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&ddev->poll_work, digital_wq_poll);
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_JEWEL_MASK)
7798c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_JEWEL_MASK;
7808c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_MIFARE_MASK)
7818c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_MIFARE_MASK;
7828c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_FELICA_MASK)
7838c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_FELICA_MASK;
7848c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_NFC_DEP_MASK)
7858c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_NFC_DEP_MASK;
7868c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_ISO15693_MASK)
7878c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_ISO15693_MASK;
7888c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_ISO14443_MASK)
7898c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_ISO14443_MASK;
7908c2ecf20Sopenharmony_ci	if (supported_protocols & NFC_PROTO_ISO14443_B_MASK)
7918c2ecf20Sopenharmony_ci		ddev->protocols |= NFC_PROTO_ISO14443_B_MASK;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
7948c2ecf20Sopenharmony_ci	ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols,
7978c2ecf20Sopenharmony_ci					    ddev->tx_headroom,
7988c2ecf20Sopenharmony_ci					    ddev->tx_tailroom);
7998c2ecf20Sopenharmony_ci	if (!ddev->nfc_dev) {
8008c2ecf20Sopenharmony_ci		pr_err("nfc_allocate_device failed\n");
8018c2ecf20Sopenharmony_ci		goto free_dev;
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	nfc_set_drvdata(ddev->nfc_dev, ddev);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	return ddev;
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cifree_dev:
8098c2ecf20Sopenharmony_ci	kfree(ddev);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	return NULL;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_digital_allocate_device);
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_civoid nfc_digital_free_device(struct nfc_digital_dev *ddev)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	nfc_free_device(ddev->nfc_dev);
8188c2ecf20Sopenharmony_ci	kfree(ddev);
8198c2ecf20Sopenharmony_ci}
8208c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_digital_free_device);
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ciint nfc_digital_register_device(struct nfc_digital_dev *ddev)
8238c2ecf20Sopenharmony_ci{
8248c2ecf20Sopenharmony_ci	return nfc_register_device(ddev->nfc_dev);
8258c2ecf20Sopenharmony_ci}
8268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_digital_register_device);
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_civoid nfc_digital_unregister_device(struct nfc_digital_dev *ddev)
8298c2ecf20Sopenharmony_ci{
8308c2ecf20Sopenharmony_ci	struct digital_cmd *cmd, *n;
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	nfc_unregister_device(ddev->nfc_dev);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	mutex_lock(&ddev->poll_lock);
8358c2ecf20Sopenharmony_ci	ddev->poll_tech_count = 0;
8368c2ecf20Sopenharmony_ci	mutex_unlock(&ddev->poll_lock);
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&ddev->poll_work);
8398c2ecf20Sopenharmony_ci	cancel_work_sync(&ddev->cmd_work);
8408c2ecf20Sopenharmony_ci	cancel_work_sync(&ddev->cmd_complete_work);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	list_for_each_entry_safe(cmd, n, &ddev->cmd_queue, queue) {
8438c2ecf20Sopenharmony_ci		list_del(&cmd->queue);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci		/* Call the command callback if any and pass it a ENODEV error.
8468c2ecf20Sopenharmony_ci		 * This gives a chance to the command issuer to free any
8478c2ecf20Sopenharmony_ci		 * allocated buffer.
8488c2ecf20Sopenharmony_ci		 */
8498c2ecf20Sopenharmony_ci		if (cmd->cmd_cb)
8508c2ecf20Sopenharmony_ci			cmd->cmd_cb(ddev, cmd->cb_context, ERR_PTR(-ENODEV));
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci		kfree(cmd->mdaa_params);
8538c2ecf20Sopenharmony_ci		kfree(cmd);
8548c2ecf20Sopenharmony_ci	}
8558c2ecf20Sopenharmony_ci}
8568c2ecf20Sopenharmony_ciEXPORT_SYMBOL(nfc_digital_unregister_device);
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
859