18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * --------------------------------------------------------------------
48c2ecf20Sopenharmony_ci * Driver for ST NFC Transceiver ST95HF
58c2ecf20Sopenharmony_ci * --------------------------------------------------------------------
68c2ecf20Sopenharmony_ci * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/err.h>
108c2ecf20Sopenharmony_ci#include <linux/gpio.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
138c2ecf20Sopenharmony_ci#include <linux/irq.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
168c2ecf20Sopenharmony_ci#include <linux/nfc.h>
178c2ecf20Sopenharmony_ci#include <linux/of_gpio.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
208c2ecf20Sopenharmony_ci#include <linux/property.h>
218c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h>
228c2ecf20Sopenharmony_ci#include <linux/wait.h>
238c2ecf20Sopenharmony_ci#include <net/nfc/digital.h>
248c2ecf20Sopenharmony_ci#include <net/nfc/nfc.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "spi.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* supported protocols */
298c2ecf20Sopenharmony_ci#define ST95HF_SUPPORTED_PROT		(NFC_PROTO_ISO14443_MASK | \
308c2ecf20Sopenharmony_ci					NFC_PROTO_ISO14443_B_MASK | \
318c2ecf20Sopenharmony_ci					NFC_PROTO_ISO15693_MASK)
328c2ecf20Sopenharmony_ci/* driver capabilities */
338c2ecf20Sopenharmony_ci#define ST95HF_CAPABILITIES		NFC_DIGITAL_DRV_CAPS_IN_CRC
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci/* Command Send Interface */
368c2ecf20Sopenharmony_ci/* ST95HF_COMMAND_SEND CMD Ids */
378c2ecf20Sopenharmony_ci#define ECHO_CMD			0x55
388c2ecf20Sopenharmony_ci#define WRITE_REGISTER_CMD		0x9
398c2ecf20Sopenharmony_ci#define PROTOCOL_SELECT_CMD		0x2
408c2ecf20Sopenharmony_ci#define SEND_RECEIVE_CMD		0x4
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* Select protocol codes */
438c2ecf20Sopenharmony_ci#define ISO15693_PROTOCOL_CODE		0x1
448c2ecf20Sopenharmony_ci#define ISO14443A_PROTOCOL_CODE		0x2
458c2ecf20Sopenharmony_ci#define ISO14443B_PROTOCOL_CODE		0x3
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * head room len is 3
498c2ecf20Sopenharmony_ci * 1 byte for control byte
508c2ecf20Sopenharmony_ci * 1 byte for cmd
518c2ecf20Sopenharmony_ci * 1 byte for size
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ci#define ST95HF_HEADROOM_LEN		3
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/*
568c2ecf20Sopenharmony_ci * tailroom is 1 for ISO14443A
578c2ecf20Sopenharmony_ci * and 0 for ISO14443B/ISO15693,
588c2ecf20Sopenharmony_ci * hence the max value 1 should be
598c2ecf20Sopenharmony_ci * taken.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_ci#define ST95HF_TAILROOM_LEN		1
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/* Command Response interface */
648c2ecf20Sopenharmony_ci#define MAX_RESPONSE_BUFFER_SIZE	280
658c2ecf20Sopenharmony_ci#define ECHORESPONSE			0x55
668c2ecf20Sopenharmony_ci#define ST95HF_ERR_MASK			0xF
678c2ecf20Sopenharmony_ci#define ST95HF_TIMEOUT_ERROR		0x87
688c2ecf20Sopenharmony_ci#define ST95HF_NFCA_CRC_ERR_MASK	0x20
698c2ecf20Sopenharmony_ci#define ST95HF_NFCB_CRC_ERR_MASK	0x01
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci/* ST95HF transmission flag values */
728c2ecf20Sopenharmony_ci#define TRFLAG_NFCA_SHORT_FRAME		0x07
738c2ecf20Sopenharmony_ci#define TRFLAG_NFCA_STD_FRAME		0x08
748c2ecf20Sopenharmony_ci#define TRFLAG_NFCA_STD_FRAME_CRC	0x28
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci/* Misc defs */
778c2ecf20Sopenharmony_ci#define HIGH				1
788c2ecf20Sopenharmony_ci#define LOW				0
798c2ecf20Sopenharmony_ci#define ISO14443A_RATS_REQ		0xE0
808c2ecf20Sopenharmony_ci#define RATS_TB1_PRESENT_MASK		0x20
818c2ecf20Sopenharmony_ci#define RATS_TA1_PRESENT_MASK		0x10
828c2ecf20Sopenharmony_ci#define TB1_FWI_MASK			0xF0
838c2ecf20Sopenharmony_ci#define WTX_REQ_FROM_TAG		0xF2
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci#define MAX_CMD_LEN			0x7
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define MAX_CMD_PARAMS			4
888c2ecf20Sopenharmony_cistruct cmd {
898c2ecf20Sopenharmony_ci	int cmd_len;
908c2ecf20Sopenharmony_ci	unsigned char cmd_id;
918c2ecf20Sopenharmony_ci	unsigned char no_cmd_params;
928c2ecf20Sopenharmony_ci	unsigned char cmd_params[MAX_CMD_PARAMS];
938c2ecf20Sopenharmony_ci	enum req_type req;
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistruct param_list {
978c2ecf20Sopenharmony_ci	int param_offset;
988c2ecf20Sopenharmony_ci	int new_param_val;
998c2ecf20Sopenharmony_ci};
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * List of top-level cmds to be used internally by the driver.
1038c2ecf20Sopenharmony_ci * All these commands are build on top of ST95HF basic commands
1048c2ecf20Sopenharmony_ci * such as SEND_RECEIVE_CMD, PROTOCOL_SELECT_CMD, etc.
1058c2ecf20Sopenharmony_ci * These top level cmds are used internally while implementing various ops of
1068c2ecf20Sopenharmony_ci * digital layer/driver probe or extending the digital framework layer for
1078c2ecf20Sopenharmony_ci * features that are not yet implemented there, for example, WTX cmd handling.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_cienum st95hf_cmd_list {
1108c2ecf20Sopenharmony_ci	CMD_ECHO,
1118c2ecf20Sopenharmony_ci	CMD_ISO14443A_CONFIG,
1128c2ecf20Sopenharmony_ci	CMD_ISO14443A_DEMOGAIN,
1138c2ecf20Sopenharmony_ci	CMD_ISO14443B_DEMOGAIN,
1148c2ecf20Sopenharmony_ci	CMD_ISO14443A_PROTOCOL_SELECT,
1158c2ecf20Sopenharmony_ci	CMD_ISO14443B_PROTOCOL_SELECT,
1168c2ecf20Sopenharmony_ci	CMD_WTX_RESPONSE,
1178c2ecf20Sopenharmony_ci	CMD_FIELD_OFF,
1188c2ecf20Sopenharmony_ci	CMD_ISO15693_PROTOCOL_SELECT,
1198c2ecf20Sopenharmony_ci};
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic const struct cmd cmd_array[] = {
1228c2ecf20Sopenharmony_ci	[CMD_ECHO] = {
1238c2ecf20Sopenharmony_ci		.cmd_len = 0x2,
1248c2ecf20Sopenharmony_ci		.cmd_id = ECHO_CMD,
1258c2ecf20Sopenharmony_ci		.no_cmd_params = 0,
1268c2ecf20Sopenharmony_ci		.req = SYNC,
1278c2ecf20Sopenharmony_ci	},
1288c2ecf20Sopenharmony_ci	[CMD_ISO14443A_CONFIG] = {
1298c2ecf20Sopenharmony_ci		.cmd_len = 0x7,
1308c2ecf20Sopenharmony_ci		.cmd_id = WRITE_REGISTER_CMD,
1318c2ecf20Sopenharmony_ci		.no_cmd_params = 0x4,
1328c2ecf20Sopenharmony_ci		.cmd_params = {0x3A, 0x00, 0x5A, 0x04},
1338c2ecf20Sopenharmony_ci		.req = SYNC,
1348c2ecf20Sopenharmony_ci	},
1358c2ecf20Sopenharmony_ci	[CMD_ISO14443A_DEMOGAIN] = {
1368c2ecf20Sopenharmony_ci		.cmd_len = 0x7,
1378c2ecf20Sopenharmony_ci		.cmd_id = WRITE_REGISTER_CMD,
1388c2ecf20Sopenharmony_ci		.no_cmd_params = 0x4,
1398c2ecf20Sopenharmony_ci		.cmd_params = {0x68, 0x01, 0x01, 0xDF},
1408c2ecf20Sopenharmony_ci		.req = SYNC,
1418c2ecf20Sopenharmony_ci	},
1428c2ecf20Sopenharmony_ci	[CMD_ISO14443B_DEMOGAIN] = {
1438c2ecf20Sopenharmony_ci		.cmd_len = 0x7,
1448c2ecf20Sopenharmony_ci		.cmd_id = WRITE_REGISTER_CMD,
1458c2ecf20Sopenharmony_ci		.no_cmd_params = 0x4,
1468c2ecf20Sopenharmony_ci		.cmd_params = {0x68, 0x01, 0x01, 0x51},
1478c2ecf20Sopenharmony_ci		.req = SYNC,
1488c2ecf20Sopenharmony_ci	},
1498c2ecf20Sopenharmony_ci	[CMD_ISO14443A_PROTOCOL_SELECT] = {
1508c2ecf20Sopenharmony_ci		.cmd_len = 0x7,
1518c2ecf20Sopenharmony_ci		.cmd_id = PROTOCOL_SELECT_CMD,
1528c2ecf20Sopenharmony_ci		.no_cmd_params = 0x4,
1538c2ecf20Sopenharmony_ci		.cmd_params = {ISO14443A_PROTOCOL_CODE, 0x00, 0x01, 0xA0},
1548c2ecf20Sopenharmony_ci		.req = SYNC,
1558c2ecf20Sopenharmony_ci	},
1568c2ecf20Sopenharmony_ci	[CMD_ISO14443B_PROTOCOL_SELECT] = {
1578c2ecf20Sopenharmony_ci		.cmd_len = 0x7,
1588c2ecf20Sopenharmony_ci		.cmd_id = PROTOCOL_SELECT_CMD,
1598c2ecf20Sopenharmony_ci		.no_cmd_params = 0x4,
1608c2ecf20Sopenharmony_ci		.cmd_params = {ISO14443B_PROTOCOL_CODE, 0x01, 0x03, 0xFF},
1618c2ecf20Sopenharmony_ci		.req = SYNC,
1628c2ecf20Sopenharmony_ci	},
1638c2ecf20Sopenharmony_ci	[CMD_WTX_RESPONSE] = {
1648c2ecf20Sopenharmony_ci		.cmd_len = 0x6,
1658c2ecf20Sopenharmony_ci		.cmd_id = SEND_RECEIVE_CMD,
1668c2ecf20Sopenharmony_ci		.no_cmd_params = 0x3,
1678c2ecf20Sopenharmony_ci		.cmd_params = {0xF2, 0x00, TRFLAG_NFCA_STD_FRAME_CRC},
1688c2ecf20Sopenharmony_ci		.req = ASYNC,
1698c2ecf20Sopenharmony_ci	},
1708c2ecf20Sopenharmony_ci	[CMD_FIELD_OFF] = {
1718c2ecf20Sopenharmony_ci		.cmd_len = 0x5,
1728c2ecf20Sopenharmony_ci		.cmd_id = PROTOCOL_SELECT_CMD,
1738c2ecf20Sopenharmony_ci		.no_cmd_params = 0x2,
1748c2ecf20Sopenharmony_ci		.cmd_params = {0x0, 0x0},
1758c2ecf20Sopenharmony_ci		.req = SYNC,
1768c2ecf20Sopenharmony_ci	},
1778c2ecf20Sopenharmony_ci	[CMD_ISO15693_PROTOCOL_SELECT] = {
1788c2ecf20Sopenharmony_ci		.cmd_len = 0x5,
1798c2ecf20Sopenharmony_ci		.cmd_id = PROTOCOL_SELECT_CMD,
1808c2ecf20Sopenharmony_ci		.no_cmd_params = 0x2,
1818c2ecf20Sopenharmony_ci		.cmd_params = {ISO15693_PROTOCOL_CODE, 0x0D},
1828c2ecf20Sopenharmony_ci		.req = SYNC,
1838c2ecf20Sopenharmony_ci	},
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/* st95_digital_cmd_complete_arg stores client context */
1878c2ecf20Sopenharmony_cistruct st95_digital_cmd_complete_arg {
1888c2ecf20Sopenharmony_ci	struct sk_buff *skb_resp;
1898c2ecf20Sopenharmony_ci	nfc_digital_cmd_complete_t complete_cb;
1908c2ecf20Sopenharmony_ci	void *cb_usrarg;
1918c2ecf20Sopenharmony_ci	bool rats;
1928c2ecf20Sopenharmony_ci};
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/*
1958c2ecf20Sopenharmony_ci * structure containing ST95HF driver specific data.
1968c2ecf20Sopenharmony_ci * @spicontext: structure containing information required
1978c2ecf20Sopenharmony_ci *	for spi communication between st95hf and host.
1988c2ecf20Sopenharmony_ci * @ddev: nfc digital device object.
1998c2ecf20Sopenharmony_ci * @nfcdev: nfc device object.
2008c2ecf20Sopenharmony_ci * @enable_gpio: gpio used to enable st95hf transceiver.
2018c2ecf20Sopenharmony_ci * @complete_cb_arg: structure to store various context information
2028c2ecf20Sopenharmony_ci *	that is passed from nfc requesting thread to the threaded ISR.
2038c2ecf20Sopenharmony_ci * @st95hf_supply: regulator "consumer" for NFC device.
2048c2ecf20Sopenharmony_ci * @sendrcv_trflag: last byte of frame send by sendrecv command
2058c2ecf20Sopenharmony_ci *	of st95hf. This byte contains transmission flag info.
2068c2ecf20Sopenharmony_ci * @exchange_lock: semaphore used for signaling the st95hf_remove
2078c2ecf20Sopenharmony_ci *	function that the last outstanding async nfc request is finished.
2088c2ecf20Sopenharmony_ci * @rm_lock: mutex for ensuring safe access of nfc digital object
2098c2ecf20Sopenharmony_ci *	from threaded ISR. Usage of this mutex avoids any race between
2108c2ecf20Sopenharmony_ci *	deletion of the object from st95hf_remove() and its access from
2118c2ecf20Sopenharmony_ci *	the threaded ISR.
2128c2ecf20Sopenharmony_ci * @nfcdev_free: flag to have the state of nfc device object.
2138c2ecf20Sopenharmony_ci *	[alive | died]
2148c2ecf20Sopenharmony_ci * @current_protocol: current nfc protocol.
2158c2ecf20Sopenharmony_ci * @current_rf_tech: current rf technology.
2168c2ecf20Sopenharmony_ci * @fwi: frame waiting index, received in reply of RATS according to
2178c2ecf20Sopenharmony_ci *	digital protocol.
2188c2ecf20Sopenharmony_ci */
2198c2ecf20Sopenharmony_cistruct st95hf_context {
2208c2ecf20Sopenharmony_ci	struct st95hf_spi_context spicontext;
2218c2ecf20Sopenharmony_ci	struct nfc_digital_dev *ddev;
2228c2ecf20Sopenharmony_ci	struct nfc_dev *nfcdev;
2238c2ecf20Sopenharmony_ci	unsigned int enable_gpio;
2248c2ecf20Sopenharmony_ci	struct st95_digital_cmd_complete_arg complete_cb_arg;
2258c2ecf20Sopenharmony_ci	struct regulator *st95hf_supply;
2268c2ecf20Sopenharmony_ci	unsigned char sendrcv_trflag;
2278c2ecf20Sopenharmony_ci	struct semaphore exchange_lock;
2288c2ecf20Sopenharmony_ci	struct mutex rm_lock;
2298c2ecf20Sopenharmony_ci	bool nfcdev_free;
2308c2ecf20Sopenharmony_ci	u8 current_protocol;
2318c2ecf20Sopenharmony_ci	u8 current_rf_tech;
2328c2ecf20Sopenharmony_ci	int fwi;
2338c2ecf20Sopenharmony_ci};
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci/*
2368c2ecf20Sopenharmony_ci * st95hf_send_recv_cmd() is for sending commands to ST95HF
2378c2ecf20Sopenharmony_ci * that are described in the cmd_array[]. It can optionally
2388c2ecf20Sopenharmony_ci * receive the response if the cmd request is of type
2398c2ecf20Sopenharmony_ci * SYNC. For that to happen caller must pass true to recv_res.
2408c2ecf20Sopenharmony_ci * For ASYNC request, recv_res is ignored and the
2418c2ecf20Sopenharmony_ci * function will never try to receive the response on behalf
2428c2ecf20Sopenharmony_ci * of the caller.
2438c2ecf20Sopenharmony_ci */
2448c2ecf20Sopenharmony_cistatic int st95hf_send_recv_cmd(struct st95hf_context *st95context,
2458c2ecf20Sopenharmony_ci				enum st95hf_cmd_list cmd,
2468c2ecf20Sopenharmony_ci				int no_modif,
2478c2ecf20Sopenharmony_ci				struct param_list *list_array,
2488c2ecf20Sopenharmony_ci				bool recv_res)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	unsigned char spi_cmd_buffer[MAX_CMD_LEN];
2518c2ecf20Sopenharmony_ci	int i, ret;
2528c2ecf20Sopenharmony_ci	struct device *dev = &st95context->spicontext.spidev->dev;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (cmd_array[cmd].cmd_len > MAX_CMD_LEN)
2558c2ecf20Sopenharmony_ci		return -EINVAL;
2568c2ecf20Sopenharmony_ci	if (cmd_array[cmd].no_cmd_params < no_modif)
2578c2ecf20Sopenharmony_ci		return -EINVAL;
2588c2ecf20Sopenharmony_ci	if (no_modif && !list_array)
2598c2ecf20Sopenharmony_ci		return -EINVAL;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	spi_cmd_buffer[0] = ST95HF_COMMAND_SEND;
2628c2ecf20Sopenharmony_ci	spi_cmd_buffer[1] = cmd_array[cmd].cmd_id;
2638c2ecf20Sopenharmony_ci	spi_cmd_buffer[2] = cmd_array[cmd].no_cmd_params;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	memcpy(&spi_cmd_buffer[3], cmd_array[cmd].cmd_params,
2668c2ecf20Sopenharmony_ci	       spi_cmd_buffer[2]);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	for (i = 0; i < no_modif; i++) {
2698c2ecf20Sopenharmony_ci		if (list_array[i].param_offset >= cmd_array[cmd].no_cmd_params)
2708c2ecf20Sopenharmony_ci			return -EINVAL;
2718c2ecf20Sopenharmony_ci		spi_cmd_buffer[3 + list_array[i].param_offset] =
2728c2ecf20Sopenharmony_ci						list_array[i].new_param_val;
2738c2ecf20Sopenharmony_ci	}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ret = st95hf_spi_send(&st95context->spicontext,
2768c2ecf20Sopenharmony_ci			      spi_cmd_buffer,
2778c2ecf20Sopenharmony_ci			      cmd_array[cmd].cmd_len,
2788c2ecf20Sopenharmony_ci			      cmd_array[cmd].req);
2798c2ecf20Sopenharmony_ci	if (ret) {
2808c2ecf20Sopenharmony_ci		dev_err(dev, "st95hf_spi_send failed with error %d\n", ret);
2818c2ecf20Sopenharmony_ci		return ret;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	if (cmd_array[cmd].req == SYNC && recv_res) {
2858c2ecf20Sopenharmony_ci		unsigned char st95hf_response_arr[2];
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci		ret = st95hf_spi_recv_response(&st95context->spicontext,
2888c2ecf20Sopenharmony_ci					       st95hf_response_arr);
2898c2ecf20Sopenharmony_ci		if (ret < 0) {
2908c2ecf20Sopenharmony_ci			dev_err(dev, "spi error from st95hf_spi_recv_response(), err = 0x%x\n",
2918c2ecf20Sopenharmony_ci				ret);
2928c2ecf20Sopenharmony_ci			return ret;
2938c2ecf20Sopenharmony_ci		}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci		if (st95hf_response_arr[0]) {
2968c2ecf20Sopenharmony_ci			dev_err(dev, "st95hf error from st95hf_spi_recv_response(), err = 0x%x\n",
2978c2ecf20Sopenharmony_ci				st95hf_response_arr[0]);
2988c2ecf20Sopenharmony_ci			return -EIO;
2998c2ecf20Sopenharmony_ci		}
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	return 0;
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int st95hf_echo_command(struct st95hf_context *st95context)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int result = 0;
3088c2ecf20Sopenharmony_ci	unsigned char echo_response;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	result = st95hf_send_recv_cmd(st95context, CMD_ECHO, 0, NULL, false);
3118c2ecf20Sopenharmony_ci	if (result)
3128c2ecf20Sopenharmony_ci		return result;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* If control reached here, response can be taken */
3158c2ecf20Sopenharmony_ci	result = st95hf_spi_recv_echo_res(&st95context->spicontext,
3168c2ecf20Sopenharmony_ci					  &echo_response);
3178c2ecf20Sopenharmony_ci	if (result) {
3188c2ecf20Sopenharmony_ci		dev_err(&st95context->spicontext.spidev->dev,
3198c2ecf20Sopenharmony_ci			"err: echo response receive error = 0x%x\n", result);
3208c2ecf20Sopenharmony_ci		return result;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (echo_response == ECHORESPONSE)
3248c2ecf20Sopenharmony_ci		return 0;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	dev_err(&st95context->spicontext.spidev->dev, "err: echo res is 0x%x\n",
3278c2ecf20Sopenharmony_ci		echo_response);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	return -EIO;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_cistatic int secondary_configuration_type4a(struct st95hf_context *stcontext)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	int result = 0;
3358c2ecf20Sopenharmony_ci	struct device *dev = &stcontext->nfcdev->dev;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	/* 14443A config setting after select protocol */
3388c2ecf20Sopenharmony_ci	result = st95hf_send_recv_cmd(stcontext,
3398c2ecf20Sopenharmony_ci				      CMD_ISO14443A_CONFIG,
3408c2ecf20Sopenharmony_ci				      0,
3418c2ecf20Sopenharmony_ci				      NULL,
3428c2ecf20Sopenharmony_ci				      true);
3438c2ecf20Sopenharmony_ci	if (result) {
3448c2ecf20Sopenharmony_ci		dev_err(dev, "type a config cmd, err = 0x%x\n", result);
3458c2ecf20Sopenharmony_ci		return result;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	/* 14443A demo gain setting */
3498c2ecf20Sopenharmony_ci	result = st95hf_send_recv_cmd(stcontext,
3508c2ecf20Sopenharmony_ci				      CMD_ISO14443A_DEMOGAIN,
3518c2ecf20Sopenharmony_ci				      0,
3528c2ecf20Sopenharmony_ci				      NULL,
3538c2ecf20Sopenharmony_ci				      true);
3548c2ecf20Sopenharmony_ci	if (result)
3558c2ecf20Sopenharmony_ci		dev_err(dev, "type a demogain cmd, err = 0x%x\n", result);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	return result;
3588c2ecf20Sopenharmony_ci}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int secondary_configuration_type4b(struct st95hf_context *stcontext)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	int result = 0;
3638c2ecf20Sopenharmony_ci	struct device *dev = &stcontext->nfcdev->dev;
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	result = st95hf_send_recv_cmd(stcontext,
3668c2ecf20Sopenharmony_ci				      CMD_ISO14443B_DEMOGAIN,
3678c2ecf20Sopenharmony_ci				      0,
3688c2ecf20Sopenharmony_ci				      NULL,
3698c2ecf20Sopenharmony_ci				      true);
3708c2ecf20Sopenharmony_ci	if (result)
3718c2ecf20Sopenharmony_ci		dev_err(dev, "type b demogain cmd, err = 0x%x\n", result);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	return result;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int st95hf_select_protocol(struct st95hf_context *stcontext, int type)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	int result = 0;
3798c2ecf20Sopenharmony_ci	struct device *dev;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	dev = &stcontext->nfcdev->dev;
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	switch (type) {
3848c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106A:
3858c2ecf20Sopenharmony_ci		stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106A;
3868c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(stcontext,
3878c2ecf20Sopenharmony_ci					      CMD_ISO14443A_PROTOCOL_SELECT,
3888c2ecf20Sopenharmony_ci					      0,
3898c2ecf20Sopenharmony_ci					      NULL,
3908c2ecf20Sopenharmony_ci					      true);
3918c2ecf20Sopenharmony_ci		if (result) {
3928c2ecf20Sopenharmony_ci			dev_err(dev, "protocol sel, err = 0x%x\n",
3938c2ecf20Sopenharmony_ci				result);
3948c2ecf20Sopenharmony_ci			return result;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci		/* secondary config. for 14443Type 4A after protocol select */
3988c2ecf20Sopenharmony_ci		result = secondary_configuration_type4a(stcontext);
3998c2ecf20Sopenharmony_ci		if (result) {
4008c2ecf20Sopenharmony_ci			dev_err(dev, "type a secondary config, err = 0x%x\n",
4018c2ecf20Sopenharmony_ci				result);
4028c2ecf20Sopenharmony_ci			return result;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci		break;
4058c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106B:
4068c2ecf20Sopenharmony_ci		stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106B;
4078c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(stcontext,
4088c2ecf20Sopenharmony_ci					      CMD_ISO14443B_PROTOCOL_SELECT,
4098c2ecf20Sopenharmony_ci					      0,
4108c2ecf20Sopenharmony_ci					      NULL,
4118c2ecf20Sopenharmony_ci					      true);
4128c2ecf20Sopenharmony_ci		if (result) {
4138c2ecf20Sopenharmony_ci			dev_err(dev, "protocol sel send, err = 0x%x\n",
4148c2ecf20Sopenharmony_ci				result);
4158c2ecf20Sopenharmony_ci			return result;
4168c2ecf20Sopenharmony_ci		}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci		/*
4198c2ecf20Sopenharmony_ci		 * delay of 5-6 ms is required after select protocol
4208c2ecf20Sopenharmony_ci		 * command in case of ISO14443 Type B
4218c2ecf20Sopenharmony_ci		 */
4228c2ecf20Sopenharmony_ci		usleep_range(50000, 60000);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		/* secondary config. for 14443Type 4B after protocol select */
4258c2ecf20Sopenharmony_ci		result = secondary_configuration_type4b(stcontext);
4268c2ecf20Sopenharmony_ci		if (result) {
4278c2ecf20Sopenharmony_ci			dev_err(dev, "type b secondary config, err = 0x%x\n",
4288c2ecf20Sopenharmony_ci				result);
4298c2ecf20Sopenharmony_ci			return result;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci		break;
4328c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_ISO15693:
4338c2ecf20Sopenharmony_ci		stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_ISO15693;
4348c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(stcontext,
4358c2ecf20Sopenharmony_ci					      CMD_ISO15693_PROTOCOL_SELECT,
4368c2ecf20Sopenharmony_ci					      0,
4378c2ecf20Sopenharmony_ci					      NULL,
4388c2ecf20Sopenharmony_ci					      true);
4398c2ecf20Sopenharmony_ci		if (result) {
4408c2ecf20Sopenharmony_ci			dev_err(dev, "protocol sel send, err = 0x%x\n",
4418c2ecf20Sopenharmony_ci				result);
4428c2ecf20Sopenharmony_ci			return result;
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci		break;
4458c2ecf20Sopenharmony_ci	default:
4468c2ecf20Sopenharmony_ci		return -EINVAL;
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return 0;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic void st95hf_send_st95enable_negativepulse(struct st95hf_context *st95con)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	/* First make irq_in pin high */
4558c2ecf20Sopenharmony_ci	gpio_set_value(st95con->enable_gpio, HIGH);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* wait for 1 milisecond */
4588c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	/* Make irq_in pin low */
4618c2ecf20Sopenharmony_ci	gpio_set_value(st95con->enable_gpio, LOW);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	/* wait for minimum interrupt pulse to make st95 active */
4648c2ecf20Sopenharmony_ci	usleep_range(1000, 2000);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* At end make it high */
4678c2ecf20Sopenharmony_ci	gpio_set_value(st95con->enable_gpio, HIGH);
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci/*
4718c2ecf20Sopenharmony_ci * Send a reset sequence over SPI bus (Reset command + wait 3ms +
4728c2ecf20Sopenharmony_ci * negative pulse on st95hf enable gpio
4738c2ecf20Sopenharmony_ci */
4748c2ecf20Sopenharmony_cistatic int st95hf_send_spi_reset_sequence(struct st95hf_context *st95context)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	int result = 0;
4778c2ecf20Sopenharmony_ci	unsigned char reset_cmd = ST95HF_COMMAND_RESET;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	result = st95hf_spi_send(&st95context->spicontext,
4808c2ecf20Sopenharmony_ci				 &reset_cmd,
4818c2ecf20Sopenharmony_ci				 ST95HF_RESET_CMD_LEN,
4828c2ecf20Sopenharmony_ci				 ASYNC);
4838c2ecf20Sopenharmony_ci	if (result) {
4848c2ecf20Sopenharmony_ci		dev_err(&st95context->spicontext.spidev->dev,
4858c2ecf20Sopenharmony_ci			"spi reset sequence cmd error = %d", result);
4868c2ecf20Sopenharmony_ci		return result;
4878c2ecf20Sopenharmony_ci	}
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/* wait for 3 milisecond to complete the controller reset process */
4908c2ecf20Sopenharmony_ci	usleep_range(3000, 4000);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* send negative pulse to make st95hf active */
4938c2ecf20Sopenharmony_ci	st95hf_send_st95enable_negativepulse(st95context);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/* wait for 10 milisecond : HFO setup time */
4968c2ecf20Sopenharmony_ci	usleep_range(10000, 20000);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return result;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic int st95hf_por_sequence(struct st95hf_context *st95context)
5028c2ecf20Sopenharmony_ci{
5038c2ecf20Sopenharmony_ci	int nth_attempt = 1;
5048c2ecf20Sopenharmony_ci	int result;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	st95hf_send_st95enable_negativepulse(st95context);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	usleep_range(5000, 6000);
5098c2ecf20Sopenharmony_ci	do {
5108c2ecf20Sopenharmony_ci		/* send an ECHO command and checks ST95HF response */
5118c2ecf20Sopenharmony_ci		result = st95hf_echo_command(st95context);
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci		dev_dbg(&st95context->spicontext.spidev->dev,
5148c2ecf20Sopenharmony_ci			"response from echo function = 0x%x, attempt = %d\n",
5158c2ecf20Sopenharmony_ci			result, nth_attempt);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci		if (!result)
5188c2ecf20Sopenharmony_ci			return 0;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci		/* send an pulse on IRQ in case of the chip is on sleep state */
5218c2ecf20Sopenharmony_ci		if (nth_attempt == 2)
5228c2ecf20Sopenharmony_ci			st95hf_send_st95enable_negativepulse(st95context);
5238c2ecf20Sopenharmony_ci		else
5248c2ecf20Sopenharmony_ci			st95hf_send_spi_reset_sequence(st95context);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		/* delay of 50 milisecond */
5278c2ecf20Sopenharmony_ci		usleep_range(50000, 51000);
5288c2ecf20Sopenharmony_ci	} while (nth_attempt++ < 3);
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_cistatic int iso14443_config_fdt(struct st95hf_context *st95context, int wtxm)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	int result = 0;
5368c2ecf20Sopenharmony_ci	struct device *dev = &st95context->spicontext.spidev->dev;
5378c2ecf20Sopenharmony_ci	struct nfc_digital_dev *nfcddev = st95context->ddev;
5388c2ecf20Sopenharmony_ci	unsigned char pp_typeb;
5398c2ecf20Sopenharmony_ci	struct param_list new_params[2];
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	pp_typeb = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[2];
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 &&
5448c2ecf20Sopenharmony_ci	    st95context->fwi < 4)
5458c2ecf20Sopenharmony_ci		st95context->fwi = 4;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	new_params[0].param_offset = 2;
5488c2ecf20Sopenharmony_ci	if (nfcddev->curr_protocol == NFC_PROTO_ISO14443)
5498c2ecf20Sopenharmony_ci		new_params[0].new_param_val = st95context->fwi;
5508c2ecf20Sopenharmony_ci	else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B)
5518c2ecf20Sopenharmony_ci		new_params[0].new_param_val = pp_typeb;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	new_params[1].param_offset = 3;
5548c2ecf20Sopenharmony_ci	new_params[1].new_param_val = wtxm;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	switch (nfcddev->curr_protocol) {
5578c2ecf20Sopenharmony_ci	case NFC_PROTO_ISO14443:
5588c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(st95context,
5598c2ecf20Sopenharmony_ci					      CMD_ISO14443A_PROTOCOL_SELECT,
5608c2ecf20Sopenharmony_ci					      2,
5618c2ecf20Sopenharmony_ci					      new_params,
5628c2ecf20Sopenharmony_ci					      true);
5638c2ecf20Sopenharmony_ci		if (result) {
5648c2ecf20Sopenharmony_ci			dev_err(dev, "WTX type a sel proto, err = 0x%x\n",
5658c2ecf20Sopenharmony_ci				result);
5668c2ecf20Sopenharmony_ci			return result;
5678c2ecf20Sopenharmony_ci		}
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		/* secondary config. for 14443Type 4A after protocol select */
5708c2ecf20Sopenharmony_ci		result = secondary_configuration_type4a(st95context);
5718c2ecf20Sopenharmony_ci		if (result) {
5728c2ecf20Sopenharmony_ci			dev_err(dev, "WTX type a second. config, err = 0x%x\n",
5738c2ecf20Sopenharmony_ci				result);
5748c2ecf20Sopenharmony_ci			return result;
5758c2ecf20Sopenharmony_ci		}
5768c2ecf20Sopenharmony_ci		break;
5778c2ecf20Sopenharmony_ci	case NFC_PROTO_ISO14443_B:
5788c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(st95context,
5798c2ecf20Sopenharmony_ci					      CMD_ISO14443B_PROTOCOL_SELECT,
5808c2ecf20Sopenharmony_ci					      2,
5818c2ecf20Sopenharmony_ci					      new_params,
5828c2ecf20Sopenharmony_ci					      true);
5838c2ecf20Sopenharmony_ci		if (result) {
5848c2ecf20Sopenharmony_ci			dev_err(dev, "WTX type b sel proto, err = 0x%x\n",
5858c2ecf20Sopenharmony_ci				result);
5868c2ecf20Sopenharmony_ci			return result;
5878c2ecf20Sopenharmony_ci		}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		/* secondary config. for 14443Type 4B after protocol select */
5908c2ecf20Sopenharmony_ci		result = secondary_configuration_type4b(st95context);
5918c2ecf20Sopenharmony_ci		if (result) {
5928c2ecf20Sopenharmony_ci			dev_err(dev, "WTX type b second. config, err = 0x%x\n",
5938c2ecf20Sopenharmony_ci				result);
5948c2ecf20Sopenharmony_ci			return result;
5958c2ecf20Sopenharmony_ci		}
5968c2ecf20Sopenharmony_ci		break;
5978c2ecf20Sopenharmony_ci	default:
5988c2ecf20Sopenharmony_ci		return -EINVAL;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return 0;
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistatic int st95hf_handle_wtx(struct st95hf_context *stcontext,
6058c2ecf20Sopenharmony_ci			     bool new_wtx,
6068c2ecf20Sopenharmony_ci			     int wtx_val)
6078c2ecf20Sopenharmony_ci{
6088c2ecf20Sopenharmony_ci	int result = 0;
6098c2ecf20Sopenharmony_ci	unsigned char val_mm = 0;
6108c2ecf20Sopenharmony_ci	struct param_list new_params[1];
6118c2ecf20Sopenharmony_ci	struct nfc_digital_dev *nfcddev = stcontext->ddev;
6128c2ecf20Sopenharmony_ci	struct device *dev = &stcontext->nfcdev->dev;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	if (new_wtx) {
6158c2ecf20Sopenharmony_ci		result = iso14443_config_fdt(stcontext, wtx_val & 0x3f);
6168c2ecf20Sopenharmony_ci		if (result) {
6178c2ecf20Sopenharmony_ci			dev_err(dev, "Config. setting error on WTX req, err = 0x%x\n",
6188c2ecf20Sopenharmony_ci				result);
6198c2ecf20Sopenharmony_ci			return result;
6208c2ecf20Sopenharmony_ci		}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		/* Send response of wtx with ASYNC as no response expected */
6238c2ecf20Sopenharmony_ci		new_params[0].param_offset = 1;
6248c2ecf20Sopenharmony_ci		new_params[0].new_param_val = wtx_val;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		result = st95hf_send_recv_cmd(stcontext,
6278c2ecf20Sopenharmony_ci					      CMD_WTX_RESPONSE,
6288c2ecf20Sopenharmony_ci					      1,
6298c2ecf20Sopenharmony_ci					      new_params,
6308c2ecf20Sopenharmony_ci					      false);
6318c2ecf20Sopenharmony_ci		if (result)
6328c2ecf20Sopenharmony_ci			dev_err(dev, "WTX response send, err = 0x%x\n", result);
6338c2ecf20Sopenharmony_ci		return result;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* if no new wtx, cofigure with default values */
6378c2ecf20Sopenharmony_ci	if (nfcddev->curr_protocol == NFC_PROTO_ISO14443)
6388c2ecf20Sopenharmony_ci		val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3];
6398c2ecf20Sopenharmony_ci	else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B)
6408c2ecf20Sopenharmony_ci		val_mm = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[3];
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	result = iso14443_config_fdt(stcontext, val_mm);
6438c2ecf20Sopenharmony_ci	if (result)
6448c2ecf20Sopenharmony_ci		dev_err(dev, "Default config. setting error after WTX processing, err = 0x%x\n",
6458c2ecf20Sopenharmony_ci			result);
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	return result;
6488c2ecf20Sopenharmony_ci}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_cistatic int st95hf_error_handling(struct st95hf_context *stcontext,
6518c2ecf20Sopenharmony_ci				 struct sk_buff *skb_resp,
6528c2ecf20Sopenharmony_ci				 int res_len)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	int result = 0;
6558c2ecf20Sopenharmony_ci	unsigned char error_byte;
6568c2ecf20Sopenharmony_ci	struct device *dev = &stcontext->nfcdev->dev;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	/* First check ST95HF specific error */
6598c2ecf20Sopenharmony_ci	if (skb_resp->data[0] & ST95HF_ERR_MASK) {
6608c2ecf20Sopenharmony_ci		if (skb_resp->data[0] == ST95HF_TIMEOUT_ERROR)
6618c2ecf20Sopenharmony_ci			result = -ETIMEDOUT;
6628c2ecf20Sopenharmony_ci		else
6638c2ecf20Sopenharmony_ci			result = -EIO;
6648c2ecf20Sopenharmony_ci		return result;
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	/* Check for CRC err only if CRC is present in the tag response */
6688c2ecf20Sopenharmony_ci	switch (stcontext->current_rf_tech) {
6698c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106A:
6708c2ecf20Sopenharmony_ci		if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC) {
6718c2ecf20Sopenharmony_ci			error_byte = skb_resp->data[res_len - 3];
6728c2ecf20Sopenharmony_ci			if (error_byte & ST95HF_NFCA_CRC_ERR_MASK) {
6738c2ecf20Sopenharmony_ci				/* CRC error occurred */
6748c2ecf20Sopenharmony_ci				dev_err(dev, "CRC error, byte received = 0x%x\n",
6758c2ecf20Sopenharmony_ci					error_byte);
6768c2ecf20Sopenharmony_ci				result = -EIO;
6778c2ecf20Sopenharmony_ci			}
6788c2ecf20Sopenharmony_ci		}
6798c2ecf20Sopenharmony_ci		break;
6808c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106B:
6818c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_ISO15693:
6828c2ecf20Sopenharmony_ci		error_byte = skb_resp->data[res_len - 1];
6838c2ecf20Sopenharmony_ci		if (error_byte & ST95HF_NFCB_CRC_ERR_MASK) {
6848c2ecf20Sopenharmony_ci			/* CRC error occurred */
6858c2ecf20Sopenharmony_ci			dev_err(dev, "CRC error, byte received = 0x%x\n",
6868c2ecf20Sopenharmony_ci				error_byte);
6878c2ecf20Sopenharmony_ci			result = -EIO;
6888c2ecf20Sopenharmony_ci		}
6898c2ecf20Sopenharmony_ci		break;
6908c2ecf20Sopenharmony_ci	}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	return result;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic int st95hf_response_handler(struct st95hf_context *stcontext,
6968c2ecf20Sopenharmony_ci				   struct sk_buff *skb_resp,
6978c2ecf20Sopenharmony_ci				   int res_len)
6988c2ecf20Sopenharmony_ci{
6998c2ecf20Sopenharmony_ci	int result = 0;
7008c2ecf20Sopenharmony_ci	int skb_len;
7018c2ecf20Sopenharmony_ci	unsigned char val_mm;
7028c2ecf20Sopenharmony_ci	struct nfc_digital_dev *nfcddev = stcontext->ddev;
7038c2ecf20Sopenharmony_ci	struct device *dev = &stcontext->nfcdev->dev;
7048c2ecf20Sopenharmony_ci	struct st95_digital_cmd_complete_arg *cb_arg;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	cb_arg = &stcontext->complete_cb_arg;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	/* Process the response */
7098c2ecf20Sopenharmony_ci	skb_put(skb_resp, res_len);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	/* Remove st95 header */
7128c2ecf20Sopenharmony_ci	skb_pull(skb_resp, 2);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	skb_len = skb_resp->len;
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_ci	/* check if it is case of RATS request reply & FWI is present */
7178c2ecf20Sopenharmony_ci	if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 && cb_arg->rats &&
7188c2ecf20Sopenharmony_ci	    (skb_resp->data[1] & RATS_TB1_PRESENT_MASK)) {
7198c2ecf20Sopenharmony_ci		if (skb_resp->data[1] & RATS_TA1_PRESENT_MASK)
7208c2ecf20Sopenharmony_ci			stcontext->fwi =
7218c2ecf20Sopenharmony_ci				(skb_resp->data[3] & TB1_FWI_MASK) >> 4;
7228c2ecf20Sopenharmony_ci		else
7238c2ecf20Sopenharmony_ci			stcontext->fwi =
7248c2ecf20Sopenharmony_ci				(skb_resp->data[2] & TB1_FWI_MASK) >> 4;
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci		val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3];
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci		result = iso14443_config_fdt(stcontext, val_mm);
7298c2ecf20Sopenharmony_ci		if (result) {
7308c2ecf20Sopenharmony_ci			dev_err(dev, "error in config_fdt to handle fwi of ATS, error=%d\n",
7318c2ecf20Sopenharmony_ci				result);
7328c2ecf20Sopenharmony_ci			return result;
7338c2ecf20Sopenharmony_ci		}
7348c2ecf20Sopenharmony_ci	}
7358c2ecf20Sopenharmony_ci	cb_arg->rats = false;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	/* Remove CRC bytes only if received frames data has an eod (CRC) */
7388c2ecf20Sopenharmony_ci	switch (stcontext->current_rf_tech) {
7398c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106A:
7408c2ecf20Sopenharmony_ci		if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC)
7418c2ecf20Sopenharmony_ci			skb_trim(skb_resp, (skb_len - 5));
7428c2ecf20Sopenharmony_ci		else
7438c2ecf20Sopenharmony_ci			skb_trim(skb_resp, (skb_len - 3));
7448c2ecf20Sopenharmony_ci		break;
7458c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106B:
7468c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_ISO15693:
7478c2ecf20Sopenharmony_ci		skb_trim(skb_resp, (skb_len - 3));
7488c2ecf20Sopenharmony_ci		break;
7498c2ecf20Sopenharmony_ci	}
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	return result;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_cistatic irqreturn_t st95hf_irq_handler(int irq, void  *st95hfcontext)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext  =
7578c2ecf20Sopenharmony_ci		(struct st95hf_context *)st95hfcontext;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (stcontext->spicontext.req_issync) {
7608c2ecf20Sopenharmony_ci		complete(&stcontext->spicontext.done);
7618c2ecf20Sopenharmony_ci		stcontext->spicontext.req_issync = false;
7628c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
7638c2ecf20Sopenharmony_ci	}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	return IRQ_WAKE_THREAD;
7668c2ecf20Sopenharmony_ci}
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistatic irqreturn_t st95hf_irq_thread_handler(int irq, void  *st95hfcontext)
7698c2ecf20Sopenharmony_ci{
7708c2ecf20Sopenharmony_ci	int result = 0;
7718c2ecf20Sopenharmony_ci	int res_len;
7728c2ecf20Sopenharmony_ci	static bool wtx;
7738c2ecf20Sopenharmony_ci	struct device *spidevice;
7748c2ecf20Sopenharmony_ci	struct sk_buff *skb_resp;
7758c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext  =
7768c2ecf20Sopenharmony_ci		(struct st95hf_context *)st95hfcontext;
7778c2ecf20Sopenharmony_ci	struct st95_digital_cmd_complete_arg *cb_arg;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	spidevice = &stcontext->spicontext.spidev->dev;
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	/*
7828c2ecf20Sopenharmony_ci	 * check semaphore, if not down() already, then we don't
7838c2ecf20Sopenharmony_ci	 * know in which context the ISR is called and surely it
7848c2ecf20Sopenharmony_ci	 * will be a bug. Note that down() of the semaphore is done
7858c2ecf20Sopenharmony_ci	 * in the corresponding st95hf_in_send_cmd() and then
7868c2ecf20Sopenharmony_ci	 * only this ISR should be called. ISR will up() the
7878c2ecf20Sopenharmony_ci	 * semaphore before leaving. Hence when the ISR is called
7888c2ecf20Sopenharmony_ci	 * the correct behaviour is down_trylock() should always
7898c2ecf20Sopenharmony_ci	 * return 1 (indicating semaphore cant be taken and hence no
7908c2ecf20Sopenharmony_ci	 * change in semaphore count).
7918c2ecf20Sopenharmony_ci	 * If not, then we up() the semaphore and crash on
7928c2ecf20Sopenharmony_ci	 * a BUG() !
7938c2ecf20Sopenharmony_ci	 */
7948c2ecf20Sopenharmony_ci	if (!down_trylock(&stcontext->exchange_lock)) {
7958c2ecf20Sopenharmony_ci		up(&stcontext->exchange_lock);
7968c2ecf20Sopenharmony_ci		WARN(1, "unknown context in ST95HF ISR");
7978c2ecf20Sopenharmony_ci		return IRQ_NONE;
7988c2ecf20Sopenharmony_ci	}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci	cb_arg = &stcontext->complete_cb_arg;
8018c2ecf20Sopenharmony_ci	skb_resp = cb_arg->skb_resp;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	mutex_lock(&stcontext->rm_lock);
8048c2ecf20Sopenharmony_ci	res_len = st95hf_spi_recv_response(&stcontext->spicontext,
8058c2ecf20Sopenharmony_ci					   skb_resp->data);
8068c2ecf20Sopenharmony_ci	if (res_len < 0) {
8078c2ecf20Sopenharmony_ci		dev_err(spidevice, "TISR spi response err = 0x%x\n", res_len);
8088c2ecf20Sopenharmony_ci		result = res_len;
8098c2ecf20Sopenharmony_ci		goto end;
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	/* if stcontext->nfcdev_free is true, it means remove already ran */
8138c2ecf20Sopenharmony_ci	if (stcontext->nfcdev_free) {
8148c2ecf20Sopenharmony_ci		result = -ENODEV;
8158c2ecf20Sopenharmony_ci		goto end;
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (skb_resp->data[2] == WTX_REQ_FROM_TAG) {
8198c2ecf20Sopenharmony_ci		/* Request for new FWT from tag */
8208c2ecf20Sopenharmony_ci		result = st95hf_handle_wtx(stcontext, true, skb_resp->data[3]);
8218c2ecf20Sopenharmony_ci		if (result)
8228c2ecf20Sopenharmony_ci			goto end;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci		wtx = true;
8258c2ecf20Sopenharmony_ci		mutex_unlock(&stcontext->rm_lock);
8268c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
8278c2ecf20Sopenharmony_ci	}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	result = st95hf_error_handling(stcontext, skb_resp, res_len);
8308c2ecf20Sopenharmony_ci	if (result)
8318c2ecf20Sopenharmony_ci		goto end;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	result = st95hf_response_handler(stcontext, skb_resp, res_len);
8348c2ecf20Sopenharmony_ci	if (result)
8358c2ecf20Sopenharmony_ci		goto end;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	/*
8388c2ecf20Sopenharmony_ci	 * If select protocol is done on wtx req. do select protocol
8398c2ecf20Sopenharmony_ci	 * again with default values
8408c2ecf20Sopenharmony_ci	 */
8418c2ecf20Sopenharmony_ci	if (wtx) {
8428c2ecf20Sopenharmony_ci		wtx = false;
8438c2ecf20Sopenharmony_ci		result = st95hf_handle_wtx(stcontext, false, 0);
8448c2ecf20Sopenharmony_ci		if (result)
8458c2ecf20Sopenharmony_ci			goto end;
8468c2ecf20Sopenharmony_ci	}
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* call digital layer callback */
8498c2ecf20Sopenharmony_ci	cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* up the semaphore before returning */
8528c2ecf20Sopenharmony_ci	up(&stcontext->exchange_lock);
8538c2ecf20Sopenharmony_ci	mutex_unlock(&stcontext->rm_lock);
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ciend:
8588c2ecf20Sopenharmony_ci	kfree_skb(skb_resp);
8598c2ecf20Sopenharmony_ci	wtx = false;
8608c2ecf20Sopenharmony_ci	cb_arg->rats = false;
8618c2ecf20Sopenharmony_ci	skb_resp = ERR_PTR(result);
8628c2ecf20Sopenharmony_ci	/* call of callback with error */
8638c2ecf20Sopenharmony_ci	cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);
8648c2ecf20Sopenharmony_ci	/* up the semaphore before returning */
8658c2ecf20Sopenharmony_ci	up(&stcontext->exchange_lock);
8668c2ecf20Sopenharmony_ci	mutex_unlock(&stcontext->rm_lock);
8678c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8688c2ecf20Sopenharmony_ci}
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci/* NFC ops functions definition */
8718c2ecf20Sopenharmony_cistatic int st95hf_in_configure_hw(struct nfc_digital_dev *ddev,
8728c2ecf20Sopenharmony_ci				  int type,
8738c2ecf20Sopenharmony_ci				  int param)
8748c2ecf20Sopenharmony_ci{
8758c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (type == NFC_DIGITAL_CONFIG_RF_TECH)
8788c2ecf20Sopenharmony_ci		return st95hf_select_protocol(stcontext, param);
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	if (type == NFC_DIGITAL_CONFIG_FRAMING) {
8818c2ecf20Sopenharmony_ci		switch (param) {
8828c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCA_SHORT:
8838c2ecf20Sopenharmony_ci			stcontext->sendrcv_trflag = TRFLAG_NFCA_SHORT_FRAME;
8848c2ecf20Sopenharmony_ci			break;
8858c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
8868c2ecf20Sopenharmony_ci			stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME;
8878c2ecf20Sopenharmony_ci			break;
8888c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCA_T4T:
8898c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
8908c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
8918c2ecf20Sopenharmony_ci			stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME_CRC;
8928c2ecf20Sopenharmony_ci			break;
8938c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_NFCB:
8948c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
8958c2ecf20Sopenharmony_ci		case NFC_DIGITAL_FRAMING_ISO15693_T5T:
8968c2ecf20Sopenharmony_ci			break;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	return 0;
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_cistatic int rf_off(struct st95hf_context *stcontext)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	int rc;
9068c2ecf20Sopenharmony_ci	struct device *dev;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	dev = &stcontext->nfcdev->dev;
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	rc = st95hf_send_recv_cmd(stcontext, CMD_FIELD_OFF, 0, NULL, true);
9118c2ecf20Sopenharmony_ci	if (rc)
9128c2ecf20Sopenharmony_ci		dev_err(dev, "protocol sel send field off, err = 0x%x\n", rc);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return rc;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
9188c2ecf20Sopenharmony_ci			      struct sk_buff *skb,
9198c2ecf20Sopenharmony_ci			      u16 timeout,
9208c2ecf20Sopenharmony_ci			      nfc_digital_cmd_complete_t cb,
9218c2ecf20Sopenharmony_ci			      void *arg)
9228c2ecf20Sopenharmony_ci{
9238c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
9248c2ecf20Sopenharmony_ci	int rc;
9258c2ecf20Sopenharmony_ci	struct sk_buff *skb_resp;
9268c2ecf20Sopenharmony_ci	int len_data_to_tag = 0;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	skb_resp = nfc_alloc_recv_skb(MAX_RESPONSE_BUFFER_SIZE, GFP_KERNEL);
9298c2ecf20Sopenharmony_ci	if (!skb_resp) {
9308c2ecf20Sopenharmony_ci		rc = -ENOMEM;
9318c2ecf20Sopenharmony_ci		goto error;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	switch (stcontext->current_rf_tech) {
9358c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106A:
9368c2ecf20Sopenharmony_ci		len_data_to_tag = skb->len + 1;
9378c2ecf20Sopenharmony_ci		skb_put_u8(skb, stcontext->sendrcv_trflag);
9388c2ecf20Sopenharmony_ci		break;
9398c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_106B:
9408c2ecf20Sopenharmony_ci	case NFC_DIGITAL_RF_TECH_ISO15693:
9418c2ecf20Sopenharmony_ci		len_data_to_tag = skb->len;
9428c2ecf20Sopenharmony_ci		break;
9438c2ecf20Sopenharmony_ci	default:
9448c2ecf20Sopenharmony_ci		rc = -EINVAL;
9458c2ecf20Sopenharmony_ci		goto free_skb_resp;
9468c2ecf20Sopenharmony_ci	}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci	skb_push(skb, 3);
9498c2ecf20Sopenharmony_ci	skb->data[0] = ST95HF_COMMAND_SEND;
9508c2ecf20Sopenharmony_ci	skb->data[1] = SEND_RECEIVE_CMD;
9518c2ecf20Sopenharmony_ci	skb->data[2] = len_data_to_tag;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	stcontext->complete_cb_arg.skb_resp = skb_resp;
9548c2ecf20Sopenharmony_ci	stcontext->complete_cb_arg.cb_usrarg = arg;
9558c2ecf20Sopenharmony_ci	stcontext->complete_cb_arg.complete_cb = cb;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	if ((skb->data[3] == ISO14443A_RATS_REQ) &&
9588c2ecf20Sopenharmony_ci	    ddev->curr_protocol == NFC_PROTO_ISO14443)
9598c2ecf20Sopenharmony_ci		stcontext->complete_cb_arg.rats = true;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	/*
9628c2ecf20Sopenharmony_ci	 * down the semaphore to indicate to remove func that an
9638c2ecf20Sopenharmony_ci	 * ISR is pending, note that it will not block here in any case.
9648c2ecf20Sopenharmony_ci	 * If found blocked, it is a BUG!
9658c2ecf20Sopenharmony_ci	 */
9668c2ecf20Sopenharmony_ci	rc = down_killable(&stcontext->exchange_lock);
9678c2ecf20Sopenharmony_ci	if (rc) {
9688c2ecf20Sopenharmony_ci		WARN(1, "Semaphore is not found up in st95hf_in_send_cmd\n");
9698c2ecf20Sopenharmony_ci		goto free_skb_resp;
9708c2ecf20Sopenharmony_ci	}
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	rc = st95hf_spi_send(&stcontext->spicontext, skb->data,
9738c2ecf20Sopenharmony_ci			     skb->len,
9748c2ecf20Sopenharmony_ci			     ASYNC);
9758c2ecf20Sopenharmony_ci	if (rc) {
9768c2ecf20Sopenharmony_ci		dev_err(&stcontext->nfcdev->dev,
9778c2ecf20Sopenharmony_ci			"Error %d trying to perform data_exchange", rc);
9788c2ecf20Sopenharmony_ci		/* up the semaphore since ISR will never come in this case */
9798c2ecf20Sopenharmony_ci		up(&stcontext->exchange_lock);
9808c2ecf20Sopenharmony_ci		goto free_skb_resp;
9818c2ecf20Sopenharmony_ci	}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	kfree_skb(skb);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	return rc;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_cifree_skb_resp:
9888c2ecf20Sopenharmony_ci	kfree_skb(skb_resp);
9898c2ecf20Sopenharmony_cierror:
9908c2ecf20Sopenharmony_ci	return rc;
9918c2ecf20Sopenharmony_ci}
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci/* p2p will be supported in a later release ! */
9948c2ecf20Sopenharmony_cistatic int st95hf_tg_configure_hw(struct nfc_digital_dev *ddev,
9958c2ecf20Sopenharmony_ci				  int type,
9968c2ecf20Sopenharmony_ci				  int param)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	return 0;
9998c2ecf20Sopenharmony_ci}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_cistatic int st95hf_tg_send_cmd(struct nfc_digital_dev *ddev,
10028c2ecf20Sopenharmony_ci			      struct sk_buff *skb,
10038c2ecf20Sopenharmony_ci			      u16 timeout,
10048c2ecf20Sopenharmony_ci			      nfc_digital_cmd_complete_t cb,
10058c2ecf20Sopenharmony_ci			      void *arg)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	return 0;
10088c2ecf20Sopenharmony_ci}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cistatic int st95hf_tg_listen(struct nfc_digital_dev *ddev,
10118c2ecf20Sopenharmony_ci			    u16 timeout,
10128c2ecf20Sopenharmony_ci			    nfc_digital_cmd_complete_t cb,
10138c2ecf20Sopenharmony_ci			    void *arg)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	return 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic int st95hf_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech)
10198c2ecf20Sopenharmony_ci{
10208c2ecf20Sopenharmony_ci	return 0;
10218c2ecf20Sopenharmony_ci}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_cistatic int st95hf_switch_rf(struct nfc_digital_dev *ddev, bool on)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	u8 rf_tech;
10268c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	rf_tech = ddev->curr_rf_tech;
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (on)
10318c2ecf20Sopenharmony_ci		/* switch on RF field */
10328c2ecf20Sopenharmony_ci		return st95hf_select_protocol(stcontext, rf_tech);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	/* switch OFF RF field */
10358c2ecf20Sopenharmony_ci	return rf_off(stcontext);
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci/* TODO st95hf_abort_cmd */
10398c2ecf20Sopenharmony_cistatic void st95hf_abort_cmd(struct nfc_digital_dev *ddev)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci}
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_cistatic struct nfc_digital_ops st95hf_nfc_digital_ops = {
10448c2ecf20Sopenharmony_ci	.in_configure_hw = st95hf_in_configure_hw,
10458c2ecf20Sopenharmony_ci	.in_send_cmd = st95hf_in_send_cmd,
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	.tg_listen = st95hf_tg_listen,
10488c2ecf20Sopenharmony_ci	.tg_configure_hw = st95hf_tg_configure_hw,
10498c2ecf20Sopenharmony_ci	.tg_send_cmd = st95hf_tg_send_cmd,
10508c2ecf20Sopenharmony_ci	.tg_get_rf_tech = st95hf_tg_get_rf_tech,
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	.switch_rf = st95hf_switch_rf,
10538c2ecf20Sopenharmony_ci	.abort_cmd = st95hf_abort_cmd,
10548c2ecf20Sopenharmony_ci};
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_cistatic const struct spi_device_id st95hf_id[] = {
10578c2ecf20Sopenharmony_ci	{ "st95hf", 0 },
10588c2ecf20Sopenharmony_ci	{}
10598c2ecf20Sopenharmony_ci};
10608c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, st95hf_id);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic const struct of_device_id st95hf_spi_of_match[] = {
10638c2ecf20Sopenharmony_ci        { .compatible = "st,st95hf" },
10648c2ecf20Sopenharmony_ci        { },
10658c2ecf20Sopenharmony_ci};
10668c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, st95hf_spi_of_match);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_cistatic int st95hf_probe(struct spi_device *nfc_spi_dev)
10698c2ecf20Sopenharmony_ci{
10708c2ecf20Sopenharmony_ci	int ret;
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	struct st95hf_context *st95context;
10738c2ecf20Sopenharmony_ci	struct st95hf_spi_context *spicontext;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	nfc_info(&nfc_spi_dev->dev, "ST95HF driver probe called.\n");
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	st95context = devm_kzalloc(&nfc_spi_dev->dev,
10788c2ecf20Sopenharmony_ci				   sizeof(struct st95hf_context),
10798c2ecf20Sopenharmony_ci				   GFP_KERNEL);
10808c2ecf20Sopenharmony_ci	if (!st95context)
10818c2ecf20Sopenharmony_ci		return -ENOMEM;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	spicontext = &st95context->spicontext;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	spicontext->spidev = nfc_spi_dev;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	st95context->fwi =
10888c2ecf20Sopenharmony_ci		cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[2];
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (device_property_present(&nfc_spi_dev->dev, "st95hfvin")) {
10918c2ecf20Sopenharmony_ci		st95context->st95hf_supply =
10928c2ecf20Sopenharmony_ci			devm_regulator_get(&nfc_spi_dev->dev,
10938c2ecf20Sopenharmony_ci					   "st95hfvin");
10948c2ecf20Sopenharmony_ci		if (IS_ERR(st95context->st95hf_supply)) {
10958c2ecf20Sopenharmony_ci			dev_err(&nfc_spi_dev->dev, "failed to acquire regulator\n");
10968c2ecf20Sopenharmony_ci			return PTR_ERR(st95context->st95hf_supply);
10978c2ecf20Sopenharmony_ci		}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci		ret = regulator_enable(st95context->st95hf_supply);
11008c2ecf20Sopenharmony_ci		if (ret) {
11018c2ecf20Sopenharmony_ci			dev_err(&nfc_spi_dev->dev, "failed to enable regulator\n");
11028c2ecf20Sopenharmony_ci			return ret;
11038c2ecf20Sopenharmony_ci		}
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	init_completion(&spicontext->done);
11078c2ecf20Sopenharmony_ci	mutex_init(&spicontext->spi_lock);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/*
11108c2ecf20Sopenharmony_ci	 * Store spicontext in spi device object for using it in
11118c2ecf20Sopenharmony_ci	 * remove function
11128c2ecf20Sopenharmony_ci	 */
11138c2ecf20Sopenharmony_ci	dev_set_drvdata(&nfc_spi_dev->dev, spicontext);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	st95context->enable_gpio =
11168c2ecf20Sopenharmony_ci		of_get_named_gpio(nfc_spi_dev->dev.of_node,
11178c2ecf20Sopenharmony_ci				  "enable-gpio",
11188c2ecf20Sopenharmony_ci				  0);
11198c2ecf20Sopenharmony_ci	if (!gpio_is_valid(st95context->enable_gpio)) {
11208c2ecf20Sopenharmony_ci		dev_err(&nfc_spi_dev->dev, "No valid enable gpio\n");
11218c2ecf20Sopenharmony_ci		ret = st95context->enable_gpio;
11228c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	ret = devm_gpio_request_one(&nfc_spi_dev->dev, st95context->enable_gpio,
11268c2ecf20Sopenharmony_ci				    GPIOF_DIR_OUT | GPIOF_INIT_HIGH,
11278c2ecf20Sopenharmony_ci				    "enable_gpio");
11288c2ecf20Sopenharmony_ci	if (ret)
11298c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	if (nfc_spi_dev->irq > 0) {
11328c2ecf20Sopenharmony_ci		if (devm_request_threaded_irq(&nfc_spi_dev->dev,
11338c2ecf20Sopenharmony_ci					      nfc_spi_dev->irq,
11348c2ecf20Sopenharmony_ci					      st95hf_irq_handler,
11358c2ecf20Sopenharmony_ci					      st95hf_irq_thread_handler,
11368c2ecf20Sopenharmony_ci					      IRQF_TRIGGER_FALLING,
11378c2ecf20Sopenharmony_ci					      "st95hf",
11388c2ecf20Sopenharmony_ci					      (void *)st95context) < 0) {
11398c2ecf20Sopenharmony_ci			dev_err(&nfc_spi_dev->dev, "err: irq request for st95hf is failed\n");
11408c2ecf20Sopenharmony_ci			ret =  -EINVAL;
11418c2ecf20Sopenharmony_ci			goto err_disable_regulator;
11428c2ecf20Sopenharmony_ci		}
11438c2ecf20Sopenharmony_ci	} else {
11448c2ecf20Sopenharmony_ci		dev_err(&nfc_spi_dev->dev, "not a valid IRQ associated with ST95HF\n");
11458c2ecf20Sopenharmony_ci		ret = -EINVAL;
11468c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	/*
11508c2ecf20Sopenharmony_ci	 * First reset SPI to handle warm reset of the system.
11518c2ecf20Sopenharmony_ci	 * It will put the ST95HF device in Power ON state
11528c2ecf20Sopenharmony_ci	 * which make the state of device identical to state
11538c2ecf20Sopenharmony_ci	 * at the time of cold reset of the system.
11548c2ecf20Sopenharmony_ci	 */
11558c2ecf20Sopenharmony_ci	ret = st95hf_send_spi_reset_sequence(st95context);
11568c2ecf20Sopenharmony_ci	if (ret) {
11578c2ecf20Sopenharmony_ci		dev_err(&nfc_spi_dev->dev, "err: spi_reset_sequence failed\n");
11588c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11598c2ecf20Sopenharmony_ci	}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* call PowerOnReset sequence of ST95hf to activate it */
11628c2ecf20Sopenharmony_ci	ret = st95hf_por_sequence(st95context);
11638c2ecf20Sopenharmony_ci	if (ret) {
11648c2ecf20Sopenharmony_ci		dev_err(&nfc_spi_dev->dev, "err: por seq failed for st95hf\n");
11658c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11668c2ecf20Sopenharmony_ci	}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci	/* create NFC dev object and register with NFC Subsystem */
11698c2ecf20Sopenharmony_ci	st95context->ddev = nfc_digital_allocate_device(&st95hf_nfc_digital_ops,
11708c2ecf20Sopenharmony_ci							ST95HF_SUPPORTED_PROT,
11718c2ecf20Sopenharmony_ci							ST95HF_CAPABILITIES,
11728c2ecf20Sopenharmony_ci							ST95HF_HEADROOM_LEN,
11738c2ecf20Sopenharmony_ci							ST95HF_TAILROOM_LEN);
11748c2ecf20Sopenharmony_ci	if (!st95context->ddev) {
11758c2ecf20Sopenharmony_ci		ret = -ENOMEM;
11768c2ecf20Sopenharmony_ci		goto err_disable_regulator;
11778c2ecf20Sopenharmony_ci	}
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_ci	st95context->nfcdev = st95context->ddev->nfc_dev;
11808c2ecf20Sopenharmony_ci	nfc_digital_set_parent_dev(st95context->ddev, &nfc_spi_dev->dev);
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci	ret =  nfc_digital_register_device(st95context->ddev);
11838c2ecf20Sopenharmony_ci	if (ret) {
11848c2ecf20Sopenharmony_ci		dev_err(&st95context->nfcdev->dev, "st95hf registration failed\n");
11858c2ecf20Sopenharmony_ci		goto err_free_digital_device;
11868c2ecf20Sopenharmony_ci	}
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	/* store st95context in nfc device object */
11898c2ecf20Sopenharmony_ci	nfc_digital_set_drvdata(st95context->ddev, st95context);
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	sema_init(&st95context->exchange_lock, 1);
11928c2ecf20Sopenharmony_ci	mutex_init(&st95context->rm_lock);
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	return ret;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_cierr_free_digital_device:
11978c2ecf20Sopenharmony_ci	nfc_digital_free_device(st95context->ddev);
11988c2ecf20Sopenharmony_cierr_disable_regulator:
11998c2ecf20Sopenharmony_ci	if (st95context->st95hf_supply)
12008c2ecf20Sopenharmony_ci		regulator_disable(st95context->st95hf_supply);
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	return ret;
12038c2ecf20Sopenharmony_ci}
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_cistatic int st95hf_remove(struct spi_device *nfc_spi_dev)
12068c2ecf20Sopenharmony_ci{
12078c2ecf20Sopenharmony_ci	int result = 0;
12088c2ecf20Sopenharmony_ci	unsigned char reset_cmd = ST95HF_COMMAND_RESET;
12098c2ecf20Sopenharmony_ci	struct st95hf_spi_context *spictx = dev_get_drvdata(&nfc_spi_dev->dev);
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	struct st95hf_context *stcontext = container_of(spictx,
12128c2ecf20Sopenharmony_ci							struct st95hf_context,
12138c2ecf20Sopenharmony_ci							spicontext);
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci	mutex_lock(&stcontext->rm_lock);
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	nfc_digital_unregister_device(stcontext->ddev);
12188c2ecf20Sopenharmony_ci	nfc_digital_free_device(stcontext->ddev);
12198c2ecf20Sopenharmony_ci	stcontext->nfcdev_free = true;
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	mutex_unlock(&stcontext->rm_lock);
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	/* if last in_send_cmd's ISR is pending, wait for it to finish */
12248c2ecf20Sopenharmony_ci	result = down_killable(&stcontext->exchange_lock);
12258c2ecf20Sopenharmony_ci	if (result == -EINTR)
12268c2ecf20Sopenharmony_ci		dev_err(&spictx->spidev->dev, "sleep for semaphore interrupted by signal\n");
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* next reset the ST95HF controller */
12298c2ecf20Sopenharmony_ci	result = st95hf_spi_send(&stcontext->spicontext,
12308c2ecf20Sopenharmony_ci				 &reset_cmd,
12318c2ecf20Sopenharmony_ci				 ST95HF_RESET_CMD_LEN,
12328c2ecf20Sopenharmony_ci				 ASYNC);
12338c2ecf20Sopenharmony_ci	if (result) {
12348c2ecf20Sopenharmony_ci		dev_err(&spictx->spidev->dev,
12358c2ecf20Sopenharmony_ci			"ST95HF reset failed in remove() err = %d\n", result);
12368c2ecf20Sopenharmony_ci		return result;
12378c2ecf20Sopenharmony_ci	}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	/* wait for 3 ms to complete the controller reset process */
12408c2ecf20Sopenharmony_ci	usleep_range(3000, 4000);
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	/* disable regulator */
12438c2ecf20Sopenharmony_ci	if (stcontext->st95hf_supply)
12448c2ecf20Sopenharmony_ci		regulator_disable(stcontext->st95hf_supply);
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	return result;
12478c2ecf20Sopenharmony_ci}
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci/* Register as SPI protocol driver */
12508c2ecf20Sopenharmony_cistatic struct spi_driver st95hf_driver = {
12518c2ecf20Sopenharmony_ci	.driver = {
12528c2ecf20Sopenharmony_ci		.name = "st95hf",
12538c2ecf20Sopenharmony_ci		.owner = THIS_MODULE,
12548c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(st95hf_spi_of_match),
12558c2ecf20Sopenharmony_ci	},
12568c2ecf20Sopenharmony_ci	.id_table = st95hf_id,
12578c2ecf20Sopenharmony_ci	.probe = st95hf_probe,
12588c2ecf20Sopenharmony_ci	.remove = st95hf_remove,
12598c2ecf20Sopenharmony_ci};
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_cimodule_spi_driver(st95hf_driver);
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ciMODULE_AUTHOR("Shikha Singh <shikha.singh@st.com>");
12648c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ST NFC Transceiver ST95HF driver");
12658c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1266