xref: /openbmc/linux/net/nfc/digital_core.c (revision 762f99f4f3cb41a775b5157dd761217beba65873)
12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24b10884eSThierry Escande /*
34b10884eSThierry Escande  * NFC Digital Protocol stack
44b10884eSThierry Escande  * Copyright (c) 2013, Intel Corporation.
54b10884eSThierry Escande  */
64b10884eSThierry Escande 
7c5da0e4aSSamuel Ortiz #define pr_fmt(fmt) "digital: %s: " fmt, __func__
8c5da0e4aSSamuel Ortiz 
94b10884eSThierry Escande #include <linux/module.h>
104b10884eSThierry Escande 
114b10884eSThierry Escande #include "digital.h"
124b10884eSThierry Escande 
1359ee2361SThierry Escande #define DIGITAL_PROTO_NFCA_RF_TECH \
14ce2e56cdSShikha Singh 	(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | \
15ce2e56cdSShikha Singh 	NFC_PROTO_NFC_DEP_MASK | NFC_PROTO_ISO14443_MASK)
1659ee2361SThierry Escande 
1724734607SMark A. Greer #define DIGITAL_PROTO_NFCB_RF_TECH	NFC_PROTO_ISO14443_B_MASK
1824734607SMark A. Greer 
197d0911c0SThierry Escande #define DIGITAL_PROTO_NFCF_RF_TECH \
207d0911c0SThierry Escande 	(NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK)
218c0695e4SThierry Escande 
22a381d482SMark A. Greer #define DIGITAL_PROTO_ISO15693_RF_TECH	NFC_PROTO_ISO15693_MASK
23a381d482SMark A. Greer 
247854a445SThierry Escande /* Delay between each poll frame (ms) */
257854a445SThierry Escande #define DIGITAL_POLL_INTERVAL 10
267854a445SThierry Escande 
2759ee2361SThierry Escande struct digital_cmd {
2859ee2361SThierry Escande 	struct list_head queue;
2959ee2361SThierry Escande 
3059ee2361SThierry Escande 	u8 type;
3159ee2361SThierry Escande 	u8 pending;
3259ee2361SThierry Escande 
3359ee2361SThierry Escande 	u16 timeout;
3459ee2361SThierry Escande 	struct sk_buff *req;
3559ee2361SThierry Escande 	struct sk_buff *resp;
361c7a4c24SThierry Escande 	struct digital_tg_mdaa_params *mdaa_params;
3759ee2361SThierry Escande 
3859ee2361SThierry Escande 	nfc_digital_cmd_complete_t cmd_cb;
3959ee2361SThierry Escande 	void *cb_context;
4059ee2361SThierry Escande };
4159ee2361SThierry Escande 
digital_skb_alloc(struct nfc_digital_dev * ddev,unsigned int len)4259ee2361SThierry Escande struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
4359ee2361SThierry Escande 				  unsigned int len)
4459ee2361SThierry Escande {
4559ee2361SThierry Escande 	struct sk_buff *skb;
4659ee2361SThierry Escande 
4759ee2361SThierry Escande 	skb = alloc_skb(len + ddev->tx_headroom + ddev->tx_tailroom,
4859ee2361SThierry Escande 			GFP_KERNEL);
4959ee2361SThierry Escande 	if (skb)
5059ee2361SThierry Escande 		skb_reserve(skb, ddev->tx_headroom);
5159ee2361SThierry Escande 
5259ee2361SThierry Escande 	return skb;
5359ee2361SThierry Escande }
5459ee2361SThierry Escande 
digital_skb_add_crc(struct sk_buff * skb,crc_func_t crc_func,u16 init,u8 bitwise_inv,u8 msb_first)552c66daecSThierry Escande void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
562c66daecSThierry Escande 			 u8 bitwise_inv, u8 msb_first)
572c66daecSThierry Escande {
582c66daecSThierry Escande 	u16 crc;
592c66daecSThierry Escande 
602c66daecSThierry Escande 	crc = crc_func(init, skb->data, skb->len);
612c66daecSThierry Escande 
622c66daecSThierry Escande 	if (bitwise_inv)
632c66daecSThierry Escande 		crc = ~crc;
642c66daecSThierry Escande 
652c66daecSThierry Escande 	if (msb_first)
662c66daecSThierry Escande 		crc = __fswab16(crc);
672c66daecSThierry Escande 
68634fef61SJohannes Berg 	skb_put_u8(skb, crc & 0xFF);
69634fef61SJohannes Berg 	skb_put_u8(skb, (crc >> 8) & 0xFF);
702c66daecSThierry Escande }
712c66daecSThierry Escande 
digital_skb_check_crc(struct sk_buff * skb,crc_func_t crc_func,u16 crc_init,u8 bitwise_inv,u8 msb_first)722c66daecSThierry Escande int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
732c66daecSThierry Escande 			  u16 crc_init, u8 bitwise_inv, u8 msb_first)
742c66daecSThierry Escande {
752c66daecSThierry Escande 	int rc;
762c66daecSThierry Escande 	u16 crc;
772c66daecSThierry Escande 
782c66daecSThierry Escande 	if (skb->len <= 2)
792c66daecSThierry Escande 		return -EIO;
802c66daecSThierry Escande 
812c66daecSThierry Escande 	crc = crc_func(crc_init, skb->data, skb->len - 2);
822c66daecSThierry Escande 
832c66daecSThierry Escande 	if (bitwise_inv)
842c66daecSThierry Escande 		crc = ~crc;
852c66daecSThierry Escande 
862c66daecSThierry Escande 	if (msb_first)
872c66daecSThierry Escande 		crc = __swab16(crc);
882c66daecSThierry Escande 
892c66daecSThierry Escande 	rc = (skb->data[skb->len - 2] - (crc & 0xFF)) +
902c66daecSThierry Escande 	     (skb->data[skb->len - 1] - ((crc >> 8) & 0xFF));
912c66daecSThierry Escande 
922c66daecSThierry Escande 	if (rc)
932c66daecSThierry Escande 		return -EIO;
942c66daecSThierry Escande 
952c66daecSThierry Escande 	skb_trim(skb, skb->len - 2);
962c66daecSThierry Escande 
972c66daecSThierry Escande 	return 0;
982c66daecSThierry Escande }
992c66daecSThierry Escande 
digital_switch_rf(struct nfc_digital_dev * ddev,bool on)10059ee2361SThierry Escande static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on)
10159ee2361SThierry Escande {
10259ee2361SThierry Escande 	ddev->ops->switch_rf(ddev, on);
10359ee2361SThierry Escande }
10459ee2361SThierry Escande 
digital_abort_cmd(struct nfc_digital_dev * ddev)10559ee2361SThierry Escande static inline void digital_abort_cmd(struct nfc_digital_dev *ddev)
10659ee2361SThierry Escande {
10759ee2361SThierry Escande 	ddev->ops->abort_cmd(ddev);
10859ee2361SThierry Escande }
10959ee2361SThierry Escande 
digital_wq_cmd_complete(struct work_struct * work)11059ee2361SThierry Escande static void digital_wq_cmd_complete(struct work_struct *work)
11159ee2361SThierry Escande {
11259ee2361SThierry Escande 	struct digital_cmd *cmd;
11359ee2361SThierry Escande 	struct nfc_digital_dev *ddev = container_of(work,
11459ee2361SThierry Escande 						    struct nfc_digital_dev,
11559ee2361SThierry Escande 						    cmd_complete_work);
11659ee2361SThierry Escande 
11759ee2361SThierry Escande 	mutex_lock(&ddev->cmd_lock);
11859ee2361SThierry Escande 
11959ee2361SThierry Escande 	cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
12059ee2361SThierry Escande 				       queue);
12159ee2361SThierry Escande 	if (!cmd) {
12259ee2361SThierry Escande 		mutex_unlock(&ddev->cmd_lock);
12359ee2361SThierry Escande 		return;
12459ee2361SThierry Escande 	}
12559ee2361SThierry Escande 
12659ee2361SThierry Escande 	list_del(&cmd->queue);
12759ee2361SThierry Escande 
12859ee2361SThierry Escande 	mutex_unlock(&ddev->cmd_lock);
12959ee2361SThierry Escande 
13059ee2361SThierry Escande 	if (!IS_ERR(cmd->resp))
13159ee2361SThierry Escande 		print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1,
13259ee2361SThierry Escande 				     cmd->resp->data, cmd->resp->len, false);
13359ee2361SThierry Escande 
13459ee2361SThierry Escande 	cmd->cmd_cb(ddev, cmd->cb_context, cmd->resp);
13559ee2361SThierry Escande 
1361c7a4c24SThierry Escande 	kfree(cmd->mdaa_params);
13759ee2361SThierry Escande 	kfree(cmd);
13859ee2361SThierry Escande 
13959ee2361SThierry Escande 	schedule_work(&ddev->cmd_work);
14059ee2361SThierry Escande }
14159ee2361SThierry Escande 
digital_send_cmd_complete(struct nfc_digital_dev * ddev,void * arg,struct sk_buff * resp)14259ee2361SThierry Escande static void digital_send_cmd_complete(struct nfc_digital_dev *ddev,
14359ee2361SThierry Escande 				      void *arg, struct sk_buff *resp)
14459ee2361SThierry Escande {
14559ee2361SThierry Escande 	struct digital_cmd *cmd = arg;
14659ee2361SThierry Escande 
14759ee2361SThierry Escande 	cmd->resp = resp;
14859ee2361SThierry Escande 
14959ee2361SThierry Escande 	schedule_work(&ddev->cmd_complete_work);
15059ee2361SThierry Escande }
15159ee2361SThierry Escande 
digital_wq_cmd(struct work_struct * work)15259ee2361SThierry Escande static void digital_wq_cmd(struct work_struct *work)
15359ee2361SThierry Escande {
15459ee2361SThierry Escande 	int rc;
15559ee2361SThierry Escande 	struct digital_cmd *cmd;
1561c7a4c24SThierry Escande 	struct digital_tg_mdaa_params *params;
15759ee2361SThierry Escande 	struct nfc_digital_dev *ddev = container_of(work,
15859ee2361SThierry Escande 						    struct nfc_digital_dev,
15959ee2361SThierry Escande 						    cmd_work);
16059ee2361SThierry Escande 
16159ee2361SThierry Escande 	mutex_lock(&ddev->cmd_lock);
16259ee2361SThierry Escande 
16359ee2361SThierry Escande 	cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
16459ee2361SThierry Escande 				       queue);
16559ee2361SThierry Escande 	if (!cmd || cmd->pending) {
16659ee2361SThierry Escande 		mutex_unlock(&ddev->cmd_lock);
16759ee2361SThierry Escande 		return;
16859ee2361SThierry Escande 	}
16959ee2361SThierry Escande 
170af66df0fSThierry Escande 	cmd->pending = 1;
171af66df0fSThierry Escande 
17259ee2361SThierry Escande 	mutex_unlock(&ddev->cmd_lock);
17359ee2361SThierry Escande 
17459ee2361SThierry Escande 	if (cmd->req)
17559ee2361SThierry Escande 		print_hex_dump_debug("DIGITAL TX: ", DUMP_PREFIX_NONE, 16, 1,
17659ee2361SThierry Escande 				     cmd->req->data, cmd->req->len, false);
17759ee2361SThierry Escande 
17859ee2361SThierry Escande 	switch (cmd->type) {
17959ee2361SThierry Escande 	case DIGITAL_CMD_IN_SEND:
18059ee2361SThierry Escande 		rc = ddev->ops->in_send_cmd(ddev, cmd->req, cmd->timeout,
18159ee2361SThierry Escande 					    digital_send_cmd_complete, cmd);
18259ee2361SThierry Escande 		break;
1831c7a4c24SThierry Escande 
1841c7a4c24SThierry Escande 	case DIGITAL_CMD_TG_SEND:
1851c7a4c24SThierry Escande 		rc = ddev->ops->tg_send_cmd(ddev, cmd->req, cmd->timeout,
1861c7a4c24SThierry Escande 					    digital_send_cmd_complete, cmd);
1871c7a4c24SThierry Escande 		break;
1881c7a4c24SThierry Escande 
1891c7a4c24SThierry Escande 	case DIGITAL_CMD_TG_LISTEN:
1901c7a4c24SThierry Escande 		rc = ddev->ops->tg_listen(ddev, cmd->timeout,
1911c7a4c24SThierry Escande 					  digital_send_cmd_complete, cmd);
1921c7a4c24SThierry Escande 		break;
1931c7a4c24SThierry Escande 
1941c7a4c24SThierry Escande 	case DIGITAL_CMD_TG_LISTEN_MDAA:
1951c7a4c24SThierry Escande 		params = cmd->mdaa_params;
1961c7a4c24SThierry Escande 
1971c7a4c24SThierry Escande 		rc = ddev->ops->tg_listen_mdaa(ddev, params, cmd->timeout,
1981c7a4c24SThierry Escande 					       digital_send_cmd_complete, cmd);
1991c7a4c24SThierry Escande 		break;
2001c7a4c24SThierry Escande 
201bf30a67cSMark A. Greer 	case DIGITAL_CMD_TG_LISTEN_MD:
202bf30a67cSMark A. Greer 		rc = ddev->ops->tg_listen_md(ddev, cmd->timeout,
203bf30a67cSMark A. Greer 					       digital_send_cmd_complete, cmd);
204bf30a67cSMark A. Greer 		break;
205bf30a67cSMark A. Greer 
20659ee2361SThierry Escande 	default:
20726042530SSamuel Ortiz 		pr_err("Unknown cmd type %d\n", cmd->type);
20859ee2361SThierry Escande 		return;
20959ee2361SThierry Escande 	}
21059ee2361SThierry Escande 
21159ee2361SThierry Escande 	if (!rc)
21259ee2361SThierry Escande 		return;
21359ee2361SThierry Escande 
21426042530SSamuel Ortiz 	pr_err("in_send_command returned err %d\n", rc);
21559ee2361SThierry Escande 
21659ee2361SThierry Escande 	mutex_lock(&ddev->cmd_lock);
21759ee2361SThierry Escande 	list_del(&cmd->queue);
21859ee2361SThierry Escande 	mutex_unlock(&ddev->cmd_lock);
21959ee2361SThierry Escande 
22059ee2361SThierry Escande 	kfree_skb(cmd->req);
2211c7a4c24SThierry Escande 	kfree(cmd->mdaa_params);
22259ee2361SThierry Escande 	kfree(cmd);
22359ee2361SThierry Escande 
22459ee2361SThierry Escande 	schedule_work(&ddev->cmd_work);
22559ee2361SThierry Escande }
22659ee2361SThierry Escande 
digital_send_cmd(struct nfc_digital_dev * ddev,u8 cmd_type,struct sk_buff * skb,struct digital_tg_mdaa_params * params,u16 timeout,nfc_digital_cmd_complete_t cmd_cb,void * cb_context)22759ee2361SThierry Escande int digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type,
2281c7a4c24SThierry Escande 		     struct sk_buff *skb, struct digital_tg_mdaa_params *params,
2291c7a4c24SThierry Escande 		     u16 timeout, nfc_digital_cmd_complete_t cmd_cb,
2301c7a4c24SThierry Escande 		     void *cb_context)
23159ee2361SThierry Escande {
23259ee2361SThierry Escande 	struct digital_cmd *cmd;
23359ee2361SThierry Escande 
234ae72c991SMarkus Elfring 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
23559ee2361SThierry Escande 	if (!cmd)
23659ee2361SThierry Escande 		return -ENOMEM;
23759ee2361SThierry Escande 
23859ee2361SThierry Escande 	cmd->type = cmd_type;
23959ee2361SThierry Escande 	cmd->timeout = timeout;
24059ee2361SThierry Escande 	cmd->req = skb;
2411c7a4c24SThierry Escande 	cmd->mdaa_params = params;
24259ee2361SThierry Escande 	cmd->cmd_cb = cmd_cb;
24359ee2361SThierry Escande 	cmd->cb_context = cb_context;
24459ee2361SThierry Escande 	INIT_LIST_HEAD(&cmd->queue);
24559ee2361SThierry Escande 
24659ee2361SThierry Escande 	mutex_lock(&ddev->cmd_lock);
24759ee2361SThierry Escande 	list_add_tail(&cmd->queue, &ddev->cmd_queue);
24859ee2361SThierry Escande 	mutex_unlock(&ddev->cmd_lock);
24959ee2361SThierry Escande 
25059ee2361SThierry Escande 	schedule_work(&ddev->cmd_work);
25159ee2361SThierry Escande 
25259ee2361SThierry Escande 	return 0;
25359ee2361SThierry Escande }
25459ee2361SThierry Escande 
digital_in_configure_hw(struct nfc_digital_dev * ddev,int type,int param)25559ee2361SThierry Escande int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
25659ee2361SThierry Escande {
25759ee2361SThierry Escande 	int rc;
25859ee2361SThierry Escande 
25959ee2361SThierry Escande 	rc = ddev->ops->in_configure_hw(ddev, type, param);
26059ee2361SThierry Escande 	if (rc)
26126042530SSamuel Ortiz 		pr_err("in_configure_hw failed: %d\n", rc);
26259ee2361SThierry Escande 
26359ee2361SThierry Escande 	return rc;
26459ee2361SThierry Escande }
26559ee2361SThierry Escande 
digital_tg_configure_hw(struct nfc_digital_dev * ddev,int type,int param)2661c7a4c24SThierry Escande int digital_tg_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
2671c7a4c24SThierry Escande {
2681c7a4c24SThierry Escande 	int rc;
2691c7a4c24SThierry Escande 
2701c7a4c24SThierry Escande 	rc = ddev->ops->tg_configure_hw(ddev, type, param);
2711c7a4c24SThierry Escande 	if (rc)
27226042530SSamuel Ortiz 		pr_err("tg_configure_hw failed: %d\n", rc);
2731c7a4c24SThierry Escande 
2741c7a4c24SThierry Escande 	return rc;
2751c7a4c24SThierry Escande }
2761c7a4c24SThierry Escande 
digital_tg_listen_mdaa(struct nfc_digital_dev * ddev,u8 rf_tech)2771c7a4c24SThierry Escande static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech)
2781c7a4c24SThierry Escande {
2791c7a4c24SThierry Escande 	struct digital_tg_mdaa_params *params;
280*58e7dcc9SZiyang Xuan 	int rc;
2811c7a4c24SThierry Escande 
282ae72c991SMarkus Elfring 	params = kzalloc(sizeof(*params), GFP_KERNEL);
2831c7a4c24SThierry Escande 	if (!params)
2841c7a4c24SThierry Escande 		return -ENOMEM;
2851c7a4c24SThierry Escande 
2861c7a4c24SThierry Escande 	params->sens_res = DIGITAL_SENS_RES_NFC_DEP;
2871c7a4c24SThierry Escande 	get_random_bytes(params->nfcid1, sizeof(params->nfcid1));
2881c7a4c24SThierry Escande 	params->sel_res = DIGITAL_SEL_RES_NFC_DEP;
2891c7a4c24SThierry Escande 
2901c7a4c24SThierry Escande 	params->nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1;
2911c7a4c24SThierry Escande 	params->nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2;
2921c7a4c24SThierry Escande 	get_random_bytes(params->nfcid2 + 2, NFC_NFCID2_MAXSIZE - 2);
2931c7a4c24SThierry Escande 	params->sc = DIGITAL_SENSF_FELICA_SC;
2941c7a4c24SThierry Escande 
295*58e7dcc9SZiyang Xuan 	rc = digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MDAA, NULL, params,
2961c7a4c24SThierry Escande 			      500, digital_tg_recv_atr_req, NULL);
297*58e7dcc9SZiyang Xuan 	if (rc)
298*58e7dcc9SZiyang Xuan 		kfree(params);
299*58e7dcc9SZiyang Xuan 
300*58e7dcc9SZiyang Xuan 	return rc;
3011c7a4c24SThierry Escande }
3021c7a4c24SThierry Escande 
digital_tg_listen_md(struct nfc_digital_dev * ddev,u8 rf_tech)303bf30a67cSMark A. Greer static int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech)
304bf30a67cSMark A. Greer {
305bf30a67cSMark A. Greer 	return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500,
306bf30a67cSMark A. Greer 				digital_tg_recv_md_req, NULL);
307bf30a67cSMark A. Greer }
308bf30a67cSMark A. Greer 
digital_target_found(struct nfc_digital_dev * ddev,struct nfc_target * target,u8 protocol)3092c66daecSThierry Escande int digital_target_found(struct nfc_digital_dev *ddev,
3102c66daecSThierry Escande 			 struct nfc_target *target, u8 protocol)
3112c66daecSThierry Escande {
3122c66daecSThierry Escande 	int rc;
3132c66daecSThierry Escande 	u8 framing;
3142c66daecSThierry Escande 	u8 rf_tech;
3150529a7adSMark A. Greer 	u8 poll_tech_count;
3162c66daecSThierry Escande 	int (*check_crc)(struct sk_buff *skb);
3172c66daecSThierry Escande 	void (*add_crc)(struct sk_buff *skb);
3182c66daecSThierry Escande 
3192c66daecSThierry Escande 	rf_tech = ddev->poll_techs[ddev->poll_tech_index].rf_tech;
3202c66daecSThierry Escande 
3212c66daecSThierry Escande 	switch (protocol) {
3222c66daecSThierry Escande 	case NFC_PROTO_JEWEL:
3232c66daecSThierry Escande 		framing = NFC_DIGITAL_FRAMING_NFCA_T1T;
3242c66daecSThierry Escande 		check_crc = digital_skb_check_crc_b;
3252c66daecSThierry Escande 		add_crc = digital_skb_add_crc_b;
3262c66daecSThierry Escande 		break;
3272c66daecSThierry Escande 
3282c66daecSThierry Escande 	case NFC_PROTO_MIFARE:
3292c66daecSThierry Escande 		framing = NFC_DIGITAL_FRAMING_NFCA_T2T;
3302c66daecSThierry Escande 		check_crc = digital_skb_check_crc_a;
3312c66daecSThierry Escande 		add_crc = digital_skb_add_crc_a;
3322c66daecSThierry Escande 		break;
3332c66daecSThierry Escande 
3348c0695e4SThierry Escande 	case NFC_PROTO_FELICA:
3358c0695e4SThierry Escande 		framing = NFC_DIGITAL_FRAMING_NFCF_T3T;
3368c0695e4SThierry Escande 		check_crc = digital_skb_check_crc_f;
3378c0695e4SThierry Escande 		add_crc = digital_skb_add_crc_f;
3388c0695e4SThierry Escande 		break;
3398c0695e4SThierry Escande 
3407d0911c0SThierry Escande 	case NFC_PROTO_NFC_DEP:
3417d0911c0SThierry Escande 		if (rf_tech == NFC_DIGITAL_RF_TECH_106A) {
3427d0911c0SThierry Escande 			framing = NFC_DIGITAL_FRAMING_NFCA_NFC_DEP;
3437d0911c0SThierry Escande 			check_crc = digital_skb_check_crc_a;
3447d0911c0SThierry Escande 			add_crc = digital_skb_add_crc_a;
3457d0911c0SThierry Escande 		} else {
3467d0911c0SThierry Escande 			framing = NFC_DIGITAL_FRAMING_NFCF_NFC_DEP;
3477d0911c0SThierry Escande 			check_crc = digital_skb_check_crc_f;
3487d0911c0SThierry Escande 			add_crc = digital_skb_add_crc_f;
3497d0911c0SThierry Escande 		}
3507d0911c0SThierry Escande 		break;
3517d0911c0SThierry Escande 
352a381d482SMark A. Greer 	case NFC_PROTO_ISO15693:
353ceeee42dSMark A. Greer 		framing = NFC_DIGITAL_FRAMING_ISO15693_T5T;
354a381d482SMark A. Greer 		check_crc = digital_skb_check_crc_b;
355a381d482SMark A. Greer 		add_crc = digital_skb_add_crc_b;
356564af14eSThierry Escande 		break;
35712e3d241SThierry Escande 
35812e3d241SThierry Escande 	case NFC_PROTO_ISO14443:
35912e3d241SThierry Escande 		framing = NFC_DIGITAL_FRAMING_NFCA_T4T;
36012e3d241SThierry Escande 		check_crc = digital_skb_check_crc_a;
36112e3d241SThierry Escande 		add_crc = digital_skb_add_crc_a;
362a381d482SMark A. Greer 		break;
363a381d482SMark A. Greer 
36424734607SMark A. Greer 	case NFC_PROTO_ISO14443_B:
36524734607SMark A. Greer 		framing = NFC_DIGITAL_FRAMING_NFCB_T4T;
36624734607SMark A. Greer 		check_crc = digital_skb_check_crc_b;
36724734607SMark A. Greer 		add_crc = digital_skb_add_crc_b;
36824734607SMark A. Greer 		break;
36924734607SMark A. Greer 
3702c66daecSThierry Escande 	default:
37126042530SSamuel Ortiz 		pr_err("Invalid protocol %d\n", protocol);
3722c66daecSThierry Escande 		return -EINVAL;
3732c66daecSThierry Escande 	}
3742c66daecSThierry Escande 
37526042530SSamuel Ortiz 	pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol);
3762c66daecSThierry Escande 
3772c66daecSThierry Escande 	ddev->curr_rf_tech = rf_tech;
3782c66daecSThierry Escande 
3792c66daecSThierry Escande 	if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
3802c66daecSThierry Escande 		ddev->skb_add_crc = digital_skb_add_crc_none;
3812c66daecSThierry Escande 		ddev->skb_check_crc = digital_skb_check_crc_none;
3822c66daecSThierry Escande 	} else {
3832c66daecSThierry Escande 		ddev->skb_add_crc = add_crc;
3842c66daecSThierry Escande 		ddev->skb_check_crc = check_crc;
3852c66daecSThierry Escande 	}
3862c66daecSThierry Escande 
3872c66daecSThierry Escande 	rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, framing);
3882c66daecSThierry Escande 	if (rc)
3892c66daecSThierry Escande 		return rc;
3902c66daecSThierry Escande 
3912c66daecSThierry Escande 	target->supported_protocols = (1 << protocol);
3922c66daecSThierry Escande 
3930529a7adSMark A. Greer 	poll_tech_count = ddev->poll_tech_count;
3942c66daecSThierry Escande 	ddev->poll_tech_count = 0;
3952c66daecSThierry Escande 
3960529a7adSMark A. Greer 	rc = nfc_targets_found(ddev->nfc_dev, target, 1);
3970529a7adSMark A. Greer 	if (rc) {
3980529a7adSMark A. Greer 		ddev->poll_tech_count = poll_tech_count;
3990529a7adSMark A. Greer 		return rc;
4000529a7adSMark A. Greer 	}
4010529a7adSMark A. Greer 
4022c66daecSThierry Escande 	return 0;
4032c66daecSThierry Escande }
4042c66daecSThierry Escande 
digital_poll_next_tech(struct nfc_digital_dev * ddev)40559ee2361SThierry Escande void digital_poll_next_tech(struct nfc_digital_dev *ddev)
40659ee2361SThierry Escande {
4079dc33705SThierry Escande 	u8 rand_mod;
4089dc33705SThierry Escande 
40959ee2361SThierry Escande 	digital_switch_rf(ddev, 0);
41059ee2361SThierry Escande 
41159ee2361SThierry Escande 	mutex_lock(&ddev->poll_lock);
41259ee2361SThierry Escande 
41359ee2361SThierry Escande 	if (!ddev->poll_tech_count) {
41459ee2361SThierry Escande 		mutex_unlock(&ddev->poll_lock);
41559ee2361SThierry Escande 		return;
41659ee2361SThierry Escande 	}
41759ee2361SThierry Escande 
4189dc33705SThierry Escande 	get_random_bytes(&rand_mod, sizeof(rand_mod));
4199dc33705SThierry Escande 	ddev->poll_tech_index = rand_mod % ddev->poll_tech_count;
42059ee2361SThierry Escande 
42159ee2361SThierry Escande 	mutex_unlock(&ddev->poll_lock);
42259ee2361SThierry Escande 
4237854a445SThierry Escande 	schedule_delayed_work(&ddev->poll_work,
4247854a445SThierry Escande 			      msecs_to_jiffies(DIGITAL_POLL_INTERVAL));
42559ee2361SThierry Escande }
42659ee2361SThierry Escande 
digital_wq_poll(struct work_struct * work)42759ee2361SThierry Escande static void digital_wq_poll(struct work_struct *work)
42859ee2361SThierry Escande {
42959ee2361SThierry Escande 	int rc;
43059ee2361SThierry Escande 	struct digital_poll_tech *poll_tech;
43159ee2361SThierry Escande 	struct nfc_digital_dev *ddev = container_of(work,
43259ee2361SThierry Escande 						    struct nfc_digital_dev,
4337854a445SThierry Escande 						    poll_work.work);
43459ee2361SThierry Escande 	mutex_lock(&ddev->poll_lock);
43559ee2361SThierry Escande 
43659ee2361SThierry Escande 	if (!ddev->poll_tech_count) {
43759ee2361SThierry Escande 		mutex_unlock(&ddev->poll_lock);
43859ee2361SThierry Escande 		return;
43959ee2361SThierry Escande 	}
44059ee2361SThierry Escande 
44159ee2361SThierry Escande 	poll_tech = &ddev->poll_techs[ddev->poll_tech_index];
44259ee2361SThierry Escande 
44359ee2361SThierry Escande 	mutex_unlock(&ddev->poll_lock);
44459ee2361SThierry Escande 
44559ee2361SThierry Escande 	rc = poll_tech->poll_func(ddev, poll_tech->rf_tech);
44659ee2361SThierry Escande 	if (rc)
44759ee2361SThierry Escande 		digital_poll_next_tech(ddev);
44859ee2361SThierry Escande }
44959ee2361SThierry Escande 
digital_add_poll_tech(struct nfc_digital_dev * ddev,u8 rf_tech,digital_poll_t poll_func)45059ee2361SThierry Escande static void digital_add_poll_tech(struct nfc_digital_dev *ddev, u8 rf_tech,
45159ee2361SThierry Escande 				  digital_poll_t poll_func)
45259ee2361SThierry Escande {
45359ee2361SThierry Escande 	struct digital_poll_tech *poll_tech;
45459ee2361SThierry Escande 
45559ee2361SThierry Escande 	if (ddev->poll_tech_count >= NFC_DIGITAL_POLL_MODE_COUNT_MAX)
45659ee2361SThierry Escande 		return;
45759ee2361SThierry Escande 
45859ee2361SThierry Escande 	poll_tech = &ddev->poll_techs[ddev->poll_tech_count++];
45959ee2361SThierry Escande 
46059ee2361SThierry Escande 	poll_tech->rf_tech = rf_tech;
46159ee2361SThierry Escande 	poll_tech->poll_func = poll_func;
46259ee2361SThierry Escande }
46359ee2361SThierry Escande 
46459ee2361SThierry Escande /**
465b6908cf7SXiongfeng Wang  * digital_start_poll - start_poll operation
4667cdda1c1SAndrew Lunn  * @nfc_dev: device to be polled
4677cdda1c1SAndrew Lunn  * @im_protocols: bitset of nfc initiator protocols to be used for polling
4687cdda1c1SAndrew Lunn  * @tm_protocols: bitset of nfc transport protocols to be used for polling
46959ee2361SThierry Escande  *
47059ee2361SThierry Escande  * For every supported protocol, the corresponding polling function is added
47159ee2361SThierry Escande  * to the table of polling technologies (ddev->poll_techs[]) using
47259ee2361SThierry Escande  * digital_add_poll_tech().
47359ee2361SThierry Escande  * When a polling function fails (by timeout or protocol error) the next one is
47459ee2361SThierry Escande  * schedule by digital_poll_next_tech() on the poll workqueue (ddev->poll_work).
47559ee2361SThierry Escande  */
digital_start_poll(struct nfc_dev * nfc_dev,__u32 im_protocols,__u32 tm_protocols)4764b10884eSThierry Escande static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
4774b10884eSThierry Escande 			      __u32 tm_protocols)
4784b10884eSThierry Escande {
47959ee2361SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
48059ee2361SThierry Escande 	u32 matching_im_protocols, matching_tm_protocols;
48159ee2361SThierry Escande 
48226042530SSamuel Ortiz 	pr_debug("protocols: im 0x%x, tm 0x%x, supported 0x%x\n", im_protocols,
48359ee2361SThierry Escande 		 tm_protocols, ddev->protocols);
48459ee2361SThierry Escande 
48559ee2361SThierry Escande 	matching_im_protocols = ddev->protocols & im_protocols;
48659ee2361SThierry Escande 	matching_tm_protocols = ddev->protocols & tm_protocols;
48759ee2361SThierry Escande 
48859ee2361SThierry Escande 	if (!matching_im_protocols && !matching_tm_protocols) {
48926042530SSamuel Ortiz 		pr_err("Unknown protocol\n");
49059ee2361SThierry Escande 		return -EINVAL;
49159ee2361SThierry Escande 	}
49259ee2361SThierry Escande 
49359ee2361SThierry Escande 	if (ddev->poll_tech_count) {
49426042530SSamuel Ortiz 		pr_err("Already polling\n");
49559ee2361SThierry Escande 		return -EBUSY;
49659ee2361SThierry Escande 	}
49759ee2361SThierry Escande 
49859ee2361SThierry Escande 	if (ddev->curr_protocol) {
49926042530SSamuel Ortiz 		pr_err("A target is already active\n");
50059ee2361SThierry Escande 		return -EBUSY;
50159ee2361SThierry Escande 	}
50259ee2361SThierry Escande 
50359ee2361SThierry Escande 	ddev->poll_tech_count = 0;
50459ee2361SThierry Escande 	ddev->poll_tech_index = 0;
50559ee2361SThierry Escande 
50659ee2361SThierry Escande 	if (matching_im_protocols & DIGITAL_PROTO_NFCA_RF_TECH)
50759ee2361SThierry Escande 		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
50859ee2361SThierry Escande 				      digital_in_send_sens_req);
50959ee2361SThierry Escande 
51024734607SMark A. Greer 	if (matching_im_protocols & DIGITAL_PROTO_NFCB_RF_TECH)
51124734607SMark A. Greer 		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106B,
51224734607SMark A. Greer 				      digital_in_send_sensb_req);
51324734607SMark A. Greer 
5144f913d46SAxel Lin 	if (matching_im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) {
5158c0695e4SThierry Escande 		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
5168c0695e4SThierry Escande 				      digital_in_send_sensf_req);
5178c0695e4SThierry Escande 
5188c0695e4SThierry Escande 		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
5198c0695e4SThierry Escande 				      digital_in_send_sensf_req);
5208c0695e4SThierry Escande 	}
5218c0695e4SThierry Escande 
522a381d482SMark A. Greer 	if (matching_im_protocols & DIGITAL_PROTO_ISO15693_RF_TECH)
523a381d482SMark A. Greer 		digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_ISO15693,
524a381d482SMark A. Greer 				      digital_in_send_iso15693_inv_req);
525a381d482SMark A. Greer 
5264f913d46SAxel Lin 	if (matching_tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
5271c7a4c24SThierry Escande 		if (ddev->ops->tg_listen_mdaa) {
5281c7a4c24SThierry Escande 			digital_add_poll_tech(ddev, 0,
5291c7a4c24SThierry Escande 					      digital_tg_listen_mdaa);
530bf30a67cSMark A. Greer 		} else if (ddev->ops->tg_listen_md) {
531bf30a67cSMark A. Greer 			digital_add_poll_tech(ddev, 0,
532bf30a67cSMark A. Greer 					      digital_tg_listen_md);
5331c7a4c24SThierry Escande 		} else {
5341c7a4c24SThierry Escande 			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
5351c7a4c24SThierry Escande 					      digital_tg_listen_nfca);
5361c7a4c24SThierry Escande 
5371c7a4c24SThierry Escande 			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
5381c7a4c24SThierry Escande 					      digital_tg_listen_nfcf);
5391c7a4c24SThierry Escande 
5401c7a4c24SThierry Escande 			digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
5411c7a4c24SThierry Escande 					      digital_tg_listen_nfcf);
5421c7a4c24SThierry Escande 		}
5431c7a4c24SThierry Escande 	}
5441c7a4c24SThierry Escande 
54559ee2361SThierry Escande 	if (!ddev->poll_tech_count) {
54626042530SSamuel Ortiz 		pr_err("Unsupported protocols: im=0x%x, tm=0x%x\n",
54759ee2361SThierry Escande 		       matching_im_protocols, matching_tm_protocols);
54859ee2361SThierry Escande 		return -EINVAL;
54959ee2361SThierry Escande 	}
55059ee2361SThierry Escande 
5517854a445SThierry Escande 	schedule_delayed_work(&ddev->poll_work, 0);
55259ee2361SThierry Escande 
55359ee2361SThierry Escande 	return 0;
5544b10884eSThierry Escande }
5554b10884eSThierry Escande 
digital_stop_poll(struct nfc_dev * nfc_dev)5564b10884eSThierry Escande static void digital_stop_poll(struct nfc_dev *nfc_dev)
5574b10884eSThierry Escande {
55859ee2361SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
55959ee2361SThierry Escande 
56059ee2361SThierry Escande 	mutex_lock(&ddev->poll_lock);
56159ee2361SThierry Escande 
56259ee2361SThierry Escande 	if (!ddev->poll_tech_count) {
56326042530SSamuel Ortiz 		pr_err("Polling operation was not running\n");
56459ee2361SThierry Escande 		mutex_unlock(&ddev->poll_lock);
56559ee2361SThierry Escande 		return;
56659ee2361SThierry Escande 	}
56759ee2361SThierry Escande 
56859ee2361SThierry Escande 	ddev->poll_tech_count = 0;
56959ee2361SThierry Escande 
57059ee2361SThierry Escande 	mutex_unlock(&ddev->poll_lock);
57159ee2361SThierry Escande 
5727854a445SThierry Escande 	cancel_delayed_work_sync(&ddev->poll_work);
57359ee2361SThierry Escande 
57459ee2361SThierry Escande 	digital_abort_cmd(ddev);
5754b10884eSThierry Escande }
5764b10884eSThierry Escande 
digital_dev_up(struct nfc_dev * nfc_dev)5774b10884eSThierry Escande static int digital_dev_up(struct nfc_dev *nfc_dev)
5784b10884eSThierry Escande {
57959ee2361SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
58059ee2361SThierry Escande 
58159ee2361SThierry Escande 	digital_switch_rf(ddev, 1);
58259ee2361SThierry Escande 
58359ee2361SThierry Escande 	return 0;
5844b10884eSThierry Escande }
5854b10884eSThierry Escande 
digital_dev_down(struct nfc_dev * nfc_dev)5864b10884eSThierry Escande static int digital_dev_down(struct nfc_dev *nfc_dev)
5874b10884eSThierry Escande {
58859ee2361SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
58959ee2361SThierry Escande 
59059ee2361SThierry Escande 	digital_switch_rf(ddev, 0);
59159ee2361SThierry Escande 
59259ee2361SThierry Escande 	return 0;
5934b10884eSThierry Escande }
5944b10884eSThierry Escande 
digital_dep_link_up(struct nfc_dev * nfc_dev,struct nfc_target * target,__u8 comm_mode,__u8 * gb,size_t gb_len)5954b10884eSThierry Escande static int digital_dep_link_up(struct nfc_dev *nfc_dev,
5964b10884eSThierry Escande 			       struct nfc_target *target,
5974b10884eSThierry Escande 			       __u8 comm_mode, __u8 *gb, size_t gb_len)
5984b10884eSThierry Escande {
5997d0911c0SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
60048e10445SThierry Escande 	int rc;
6017d0911c0SThierry Escande 
60248e10445SThierry Escande 	rc = digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
60348e10445SThierry Escande 
60448e10445SThierry Escande 	if (!rc)
60548e10445SThierry Escande 		ddev->curr_protocol = NFC_PROTO_NFC_DEP;
60648e10445SThierry Escande 
60748e10445SThierry Escande 	return rc;
6084b10884eSThierry Escande }
6094b10884eSThierry Escande 
digital_dep_link_down(struct nfc_dev * nfc_dev)6104b10884eSThierry Escande static int digital_dep_link_down(struct nfc_dev *nfc_dev)
6114b10884eSThierry Escande {
6127d0911c0SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
6137d0911c0SThierry Escande 
6143cc952dbSThierry Escande 	digital_abort_cmd(ddev);
6153cc952dbSThierry Escande 
6167d0911c0SThierry Escande 	ddev->curr_protocol = 0;
6177d0911c0SThierry Escande 
6187d0911c0SThierry Escande 	return 0;
6194b10884eSThierry Escande }
6204b10884eSThierry Escande 
digital_activate_target(struct nfc_dev * nfc_dev,struct nfc_target * target,__u32 protocol)6214b10884eSThierry Escande static int digital_activate_target(struct nfc_dev *nfc_dev,
6224b10884eSThierry Escande 				   struct nfc_target *target, __u32 protocol)
6234b10884eSThierry Escande {
62448e10445SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
62548e10445SThierry Escande 
62648e10445SThierry Escande 	if (ddev->poll_tech_count) {
62748e10445SThierry Escande 		pr_err("Can't activate a target while polling\n");
62848e10445SThierry Escande 		return -EBUSY;
62948e10445SThierry Escande 	}
63048e10445SThierry Escande 
63148e10445SThierry Escande 	if (ddev->curr_protocol) {
63248e10445SThierry Escande 		pr_err("A target is already active\n");
63348e10445SThierry Escande 		return -EBUSY;
63448e10445SThierry Escande 	}
63548e10445SThierry Escande 
63648e10445SThierry Escande 	ddev->curr_protocol = protocol;
63748e10445SThierry Escande 
63859ee2361SThierry Escande 	return 0;
6394b10884eSThierry Escande }
6404b10884eSThierry Escande 
digital_deactivate_target(struct nfc_dev * nfc_dev,struct nfc_target * target,u8 mode)6414b10884eSThierry Escande static void digital_deactivate_target(struct nfc_dev *nfc_dev,
64296d4581fSChristophe Ricard 				      struct nfc_target *target,
64396d4581fSChristophe Ricard 				      u8 mode)
6444b10884eSThierry Escande {
64559ee2361SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
64659ee2361SThierry Escande 
64748e10445SThierry Escande 	if (!ddev->curr_protocol) {
64848e10445SThierry Escande 		pr_err("No active target\n");
64948e10445SThierry Escande 		return;
65048e10445SThierry Escande 	}
65148e10445SThierry Escande 
65272ad533aSMark Greer 	digital_abort_cmd(ddev);
65359ee2361SThierry Escande 	ddev->curr_protocol = 0;
6544b10884eSThierry Escande }
6554b10884eSThierry Escande 
digital_tg_send(struct nfc_dev * dev,struct sk_buff * skb)6564b10884eSThierry Escande static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb)
6574b10884eSThierry Escande {
6581c7a4c24SThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(dev);
6591c7a4c24SThierry Escande 
6601c7a4c24SThierry Escande 	return digital_tg_send_dep_res(ddev, skb);
6614b10884eSThierry Escande }
6624b10884eSThierry Escande 
digital_in_send_complete(struct nfc_digital_dev * ddev,void * arg,struct sk_buff * resp)6632c66daecSThierry Escande static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
6642c66daecSThierry Escande 				     struct sk_buff *resp)
6652c66daecSThierry Escande {
6662c66daecSThierry Escande 	struct digital_data_exch *data_exch = arg;
6672c66daecSThierry Escande 	int rc;
6682c66daecSThierry Escande 
6692c66daecSThierry Escande 	if (IS_ERR(resp)) {
6702c66daecSThierry Escande 		rc = PTR_ERR(resp);
671c813007fSThierry Escande 		resp = NULL;
6722c66daecSThierry Escande 		goto done;
6732c66daecSThierry Escande 	}
6742c66daecSThierry Escande 
675c813007fSThierry Escande 	if (ddev->curr_protocol == NFC_PROTO_MIFARE) {
6762c66daecSThierry Escande 		rc = digital_in_recv_mifare_res(resp);
677c813007fSThierry Escande 		/* crc check is done in digital_in_recv_mifare_res() */
678c813007fSThierry Escande 		goto done;
679c813007fSThierry Escande 	}
680c813007fSThierry Escande 
68124734607SMark A. Greer 	if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
68224734607SMark A. Greer 	    (ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
683c813007fSThierry Escande 		rc = digital_in_iso_dep_pull_sod(ddev, resp);
684c813007fSThierry Escande 		if (rc)
685c813007fSThierry Escande 			goto done;
686c813007fSThierry Escande 	}
687c813007fSThierry Escande 
6882c66daecSThierry Escande 	rc = ddev->skb_check_crc(resp);
6892c66daecSThierry Escande 
690c813007fSThierry Escande done:
6912c66daecSThierry Escande 	if (rc) {
6922c66daecSThierry Escande 		kfree_skb(resp);
6932c66daecSThierry Escande 		resp = NULL;
6942c66daecSThierry Escande 	}
6952c66daecSThierry Escande 
6962c66daecSThierry Escande 	data_exch->cb(data_exch->cb_context, resp, rc);
6972c66daecSThierry Escande 
6982c66daecSThierry Escande 	kfree(data_exch);
6992c66daecSThierry Escande }
7002c66daecSThierry Escande 
digital_in_send(struct nfc_dev * nfc_dev,struct nfc_target * target,struct sk_buff * skb,data_exchange_cb_t cb,void * cb_context)7014b10884eSThierry Escande static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
7024b10884eSThierry Escande 			   struct sk_buff *skb, data_exchange_cb_t cb,
7034b10884eSThierry Escande 			   void *cb_context)
7044b10884eSThierry Escande {
7052c66daecSThierry Escande 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
7062c66daecSThierry Escande 	struct digital_data_exch *data_exch;
707c813007fSThierry Escande 	int rc;
7082c66daecSThierry Escande 
709ae72c991SMarkus Elfring 	data_exch = kzalloc(sizeof(*data_exch), GFP_KERNEL);
710dcfca27fSMarkus Elfring 	if (!data_exch)
7112c66daecSThierry Escande 		return -ENOMEM;
7122c66daecSThierry Escande 
7132c66daecSThierry Escande 	data_exch->cb = cb;
7142c66daecSThierry Escande 	data_exch->cb_context = cb_context;
7152c66daecSThierry Escande 
7166ea7398dSThierry Escande 	if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) {
7176ea7398dSThierry Escande 		rc = digital_in_send_dep_req(ddev, target, skb, data_exch);
7186ea7398dSThierry Escande 		goto exit;
7196ea7398dSThierry Escande 	}
7207d0911c0SThierry Escande 
72124734607SMark A. Greer 	if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
72224734607SMark A. Greer 	    (ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
723c813007fSThierry Escande 		rc = digital_in_iso_dep_push_sod(ddev, skb);
724c813007fSThierry Escande 		if (rc)
7256ea7398dSThierry Escande 			goto exit;
726c813007fSThierry Escande 	}
727c813007fSThierry Escande 
7282c66daecSThierry Escande 	ddev->skb_add_crc(skb);
7292c66daecSThierry Escande 
7306ea7398dSThierry Escande 	rc = digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete,
7312c66daecSThierry Escande 				 data_exch);
7326ea7398dSThierry Escande 
7336ea7398dSThierry Escande exit:
7346ea7398dSThierry Escande 	if (rc)
7356ea7398dSThierry Escande 		kfree(data_exch);
7366ea7398dSThierry Escande 
7376ea7398dSThierry Escande 	return rc;
7384b10884eSThierry Escande }
7394b10884eSThierry Escande 
740f6c802a7SKrzysztof Kozlowski static const struct nfc_ops digital_nfc_ops = {
7414b10884eSThierry Escande 	.dev_up = digital_dev_up,
7424b10884eSThierry Escande 	.dev_down = digital_dev_down,
7434b10884eSThierry Escande 	.start_poll = digital_start_poll,
7444b10884eSThierry Escande 	.stop_poll = digital_stop_poll,
7454b10884eSThierry Escande 	.dep_link_up = digital_dep_link_up,
7464b10884eSThierry Escande 	.dep_link_down = digital_dep_link_down,
7474b10884eSThierry Escande 	.activate_target = digital_activate_target,
7484b10884eSThierry Escande 	.deactivate_target = digital_deactivate_target,
7494b10884eSThierry Escande 	.tm_send = digital_tg_send,
7504b10884eSThierry Escande 	.im_transceive = digital_in_send,
7514b10884eSThierry Escande };
7524b10884eSThierry Escande 
nfc_digital_allocate_device(const struct nfc_digital_ops * ops,__u32 supported_protocols,__u32 driver_capabilities,int tx_headroom,int tx_tailroom)7537186aac9SKrzysztof Kozlowski struct nfc_digital_dev *nfc_digital_allocate_device(const struct nfc_digital_ops *ops,
7544b10884eSThierry Escande 					    __u32 supported_protocols,
7554b10884eSThierry Escande 					    __u32 driver_capabilities,
7564b10884eSThierry Escande 					    int tx_headroom, int tx_tailroom)
7574b10884eSThierry Escande {
7584b10884eSThierry Escande 	struct nfc_digital_dev *ddev;
7594b10884eSThierry Escande 
7604b10884eSThierry Escande 	if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen ||
7614b10884eSThierry Escande 	    !ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd ||
762bf30a67cSMark A. Greer 	    !ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech))
7634b10884eSThierry Escande 		return NULL;
7644b10884eSThierry Escande 
765ae72c991SMarkus Elfring 	ddev = kzalloc(sizeof(*ddev), GFP_KERNEL);
76626042530SSamuel Ortiz 	if (!ddev)
7674b10884eSThierry Escande 		return NULL;
7684b10884eSThierry Escande 
7694b10884eSThierry Escande 	ddev->driver_capabilities = driver_capabilities;
7704b10884eSThierry Escande 	ddev->ops = ops;
7714b10884eSThierry Escande 
77259ee2361SThierry Escande 	mutex_init(&ddev->cmd_lock);
77359ee2361SThierry Escande 	INIT_LIST_HEAD(&ddev->cmd_queue);
77459ee2361SThierry Escande 
77559ee2361SThierry Escande 	INIT_WORK(&ddev->cmd_work, digital_wq_cmd);
77659ee2361SThierry Escande 	INIT_WORK(&ddev->cmd_complete_work, digital_wq_cmd_complete);
77759ee2361SThierry Escande 
77859ee2361SThierry Escande 	mutex_init(&ddev->poll_lock);
7797854a445SThierry Escande 	INIT_DELAYED_WORK(&ddev->poll_work, digital_wq_poll);
78059ee2361SThierry Escande 
78159ee2361SThierry Escande 	if (supported_protocols & NFC_PROTO_JEWEL_MASK)
78259ee2361SThierry Escande 		ddev->protocols |= NFC_PROTO_JEWEL_MASK;
78359ee2361SThierry Escande 	if (supported_protocols & NFC_PROTO_MIFARE_MASK)
78459ee2361SThierry Escande 		ddev->protocols |= NFC_PROTO_MIFARE_MASK;
7858c0695e4SThierry Escande 	if (supported_protocols & NFC_PROTO_FELICA_MASK)
7868c0695e4SThierry Escande 		ddev->protocols |= NFC_PROTO_FELICA_MASK;
7877d0911c0SThierry Escande 	if (supported_protocols & NFC_PROTO_NFC_DEP_MASK)
7887d0911c0SThierry Escande 		ddev->protocols |= NFC_PROTO_NFC_DEP_MASK;
789a381d482SMark A. Greer 	if (supported_protocols & NFC_PROTO_ISO15693_MASK)
790a381d482SMark A. Greer 		ddev->protocols |= NFC_PROTO_ISO15693_MASK;
79112e3d241SThierry Escande 	if (supported_protocols & NFC_PROTO_ISO14443_MASK)
79212e3d241SThierry Escande 		ddev->protocols |= NFC_PROTO_ISO14443_MASK;
79324734607SMark A. Greer 	if (supported_protocols & NFC_PROTO_ISO14443_B_MASK)
79424734607SMark A. Greer 		ddev->protocols |= NFC_PROTO_ISO14443_B_MASK;
79559ee2361SThierry Escande 
79659ee2361SThierry Escande 	ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
79759ee2361SThierry Escande 	ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
7984b10884eSThierry Escande 
7994b10884eSThierry Escande 	ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols,
8004b10884eSThierry Escande 					    ddev->tx_headroom,
8014b10884eSThierry Escande 					    ddev->tx_tailroom);
8024b10884eSThierry Escande 	if (!ddev->nfc_dev) {
80326042530SSamuel Ortiz 		pr_err("nfc_allocate_device failed\n");
8044b10884eSThierry Escande 		goto free_dev;
8054b10884eSThierry Escande 	}
8064b10884eSThierry Escande 
8074b10884eSThierry Escande 	nfc_set_drvdata(ddev->nfc_dev, ddev);
8084b10884eSThierry Escande 
8094b10884eSThierry Escande 	return ddev;
8104b10884eSThierry Escande 
8114b10884eSThierry Escande free_dev:
8124b10884eSThierry Escande 	kfree(ddev);
8134b10884eSThierry Escande 
8144b10884eSThierry Escande 	return NULL;
8154b10884eSThierry Escande }
8164b10884eSThierry Escande EXPORT_SYMBOL(nfc_digital_allocate_device);
8174b10884eSThierry Escande 
nfc_digital_free_device(struct nfc_digital_dev * ddev)8184b10884eSThierry Escande void nfc_digital_free_device(struct nfc_digital_dev *ddev)
8194b10884eSThierry Escande {
8204b10884eSThierry Escande 	nfc_free_device(ddev->nfc_dev);
8214b10884eSThierry Escande 	kfree(ddev);
8224b10884eSThierry Escande }
8234b10884eSThierry Escande EXPORT_SYMBOL(nfc_digital_free_device);
8244b10884eSThierry Escande 
nfc_digital_register_device(struct nfc_digital_dev * ddev)8254b10884eSThierry Escande int nfc_digital_register_device(struct nfc_digital_dev *ddev)
8264b10884eSThierry Escande {
8274b10884eSThierry Escande 	return nfc_register_device(ddev->nfc_dev);
8284b10884eSThierry Escande }
8294b10884eSThierry Escande EXPORT_SYMBOL(nfc_digital_register_device);
8304b10884eSThierry Escande 
nfc_digital_unregister_device(struct nfc_digital_dev * ddev)8314b10884eSThierry Escande void nfc_digital_unregister_device(struct nfc_digital_dev *ddev)
8324b10884eSThierry Escande {
83359ee2361SThierry Escande 	struct digital_cmd *cmd, *n;
83459ee2361SThierry Escande 
8354b10884eSThierry Escande 	nfc_unregister_device(ddev->nfc_dev);
83659ee2361SThierry Escande 
83759ee2361SThierry Escande 	mutex_lock(&ddev->poll_lock);
83859ee2361SThierry Escande 	ddev->poll_tech_count = 0;
83959ee2361SThierry Escande 	mutex_unlock(&ddev->poll_lock);
84059ee2361SThierry Escande 
8417854a445SThierry Escande 	cancel_delayed_work_sync(&ddev->poll_work);
84259ee2361SThierry Escande 	cancel_work_sync(&ddev->cmd_work);
84359ee2361SThierry Escande 	cancel_work_sync(&ddev->cmd_complete_work);
84459ee2361SThierry Escande 
84559ee2361SThierry Escande 	list_for_each_entry_safe(cmd, n, &ddev->cmd_queue, queue) {
84659ee2361SThierry Escande 		list_del(&cmd->queue);
84782e57952SThierry Escande 
84882e57952SThierry Escande 		/* Call the command callback if any and pass it a ENODEV error.
84982e57952SThierry Escande 		 * This gives a chance to the command issuer to free any
85082e57952SThierry Escande 		 * allocated buffer.
85182e57952SThierry Escande 		 */
85282e57952SThierry Escande 		if (cmd->cmd_cb)
85382e57952SThierry Escande 			cmd->cmd_cb(ddev, cmd->cb_context, ERR_PTR(-ENODEV));
85482e57952SThierry Escande 
8551c7a4c24SThierry Escande 		kfree(cmd->mdaa_params);
85659ee2361SThierry Escande 		kfree(cmd);
85759ee2361SThierry Escande 	}
8584b10884eSThierry Escande }
8594b10884eSThierry Escande EXPORT_SYMBOL(nfc_digital_unregister_device);
8604b10884eSThierry Escande 
8614b10884eSThierry Escande MODULE_LICENSE("GPL");
862