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