162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * -------------------------------------------------------------------- 462306a36Sopenharmony_ci * Driver for ST NFC Transceiver ST95HF 562306a36Sopenharmony_ci * -------------------------------------------------------------------- 662306a36Sopenharmony_ci * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/gpio.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/irq.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/netdevice.h> 1662306a36Sopenharmony_ci#include <linux/nfc.h> 1762306a36Sopenharmony_ci#include <linux/of_gpio.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/property.h> 2062306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2162306a36Sopenharmony_ci#include <linux/wait.h> 2262306a36Sopenharmony_ci#include <net/nfc/digital.h> 2362306a36Sopenharmony_ci#include <net/nfc/nfc.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "spi.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* supported protocols */ 2862306a36Sopenharmony_ci#define ST95HF_SUPPORTED_PROT (NFC_PROTO_ISO14443_MASK | \ 2962306a36Sopenharmony_ci NFC_PROTO_ISO14443_B_MASK | \ 3062306a36Sopenharmony_ci NFC_PROTO_ISO15693_MASK) 3162306a36Sopenharmony_ci/* driver capabilities */ 3262306a36Sopenharmony_ci#define ST95HF_CAPABILITIES NFC_DIGITAL_DRV_CAPS_IN_CRC 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Command Send Interface */ 3562306a36Sopenharmony_ci/* ST95HF_COMMAND_SEND CMD Ids */ 3662306a36Sopenharmony_ci#define ECHO_CMD 0x55 3762306a36Sopenharmony_ci#define WRITE_REGISTER_CMD 0x9 3862306a36Sopenharmony_ci#define PROTOCOL_SELECT_CMD 0x2 3962306a36Sopenharmony_ci#define SEND_RECEIVE_CMD 0x4 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci/* Select protocol codes */ 4262306a36Sopenharmony_ci#define ISO15693_PROTOCOL_CODE 0x1 4362306a36Sopenharmony_ci#define ISO14443A_PROTOCOL_CODE 0x2 4462306a36Sopenharmony_ci#define ISO14443B_PROTOCOL_CODE 0x3 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* 4762306a36Sopenharmony_ci * head room len is 3 4862306a36Sopenharmony_ci * 1 byte for control byte 4962306a36Sopenharmony_ci * 1 byte for cmd 5062306a36Sopenharmony_ci * 1 byte for size 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci#define ST95HF_HEADROOM_LEN 3 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * tailroom is 1 for ISO14443A 5662306a36Sopenharmony_ci * and 0 for ISO14443B/ISO15693, 5762306a36Sopenharmony_ci * hence the max value 1 should be 5862306a36Sopenharmony_ci * taken. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci#define ST95HF_TAILROOM_LEN 1 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Command Response interface */ 6362306a36Sopenharmony_ci#define MAX_RESPONSE_BUFFER_SIZE 280 6462306a36Sopenharmony_ci#define ECHORESPONSE 0x55 6562306a36Sopenharmony_ci#define ST95HF_ERR_MASK 0xF 6662306a36Sopenharmony_ci#define ST95HF_TIMEOUT_ERROR 0x87 6762306a36Sopenharmony_ci#define ST95HF_NFCA_CRC_ERR_MASK 0x20 6862306a36Sopenharmony_ci#define ST95HF_NFCB_CRC_ERR_MASK 0x01 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* ST95HF transmission flag values */ 7162306a36Sopenharmony_ci#define TRFLAG_NFCA_SHORT_FRAME 0x07 7262306a36Sopenharmony_ci#define TRFLAG_NFCA_STD_FRAME 0x08 7362306a36Sopenharmony_ci#define TRFLAG_NFCA_STD_FRAME_CRC 0x28 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Misc defs */ 7662306a36Sopenharmony_ci#define HIGH 1 7762306a36Sopenharmony_ci#define LOW 0 7862306a36Sopenharmony_ci#define ISO14443A_RATS_REQ 0xE0 7962306a36Sopenharmony_ci#define RATS_TB1_PRESENT_MASK 0x20 8062306a36Sopenharmony_ci#define RATS_TA1_PRESENT_MASK 0x10 8162306a36Sopenharmony_ci#define TB1_FWI_MASK 0xF0 8262306a36Sopenharmony_ci#define WTX_REQ_FROM_TAG 0xF2 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define MAX_CMD_LEN 0x7 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define MAX_CMD_PARAMS 4 8762306a36Sopenharmony_cistruct cmd { 8862306a36Sopenharmony_ci int cmd_len; 8962306a36Sopenharmony_ci unsigned char cmd_id; 9062306a36Sopenharmony_ci unsigned char no_cmd_params; 9162306a36Sopenharmony_ci unsigned char cmd_params[MAX_CMD_PARAMS]; 9262306a36Sopenharmony_ci enum req_type req; 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistruct param_list { 9662306a36Sopenharmony_ci int param_offset; 9762306a36Sopenharmony_ci int new_param_val; 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * List of top-level cmds to be used internally by the driver. 10262306a36Sopenharmony_ci * All these commands are build on top of ST95HF basic commands 10362306a36Sopenharmony_ci * such as SEND_RECEIVE_CMD, PROTOCOL_SELECT_CMD, etc. 10462306a36Sopenharmony_ci * These top level cmds are used internally while implementing various ops of 10562306a36Sopenharmony_ci * digital layer/driver probe or extending the digital framework layer for 10662306a36Sopenharmony_ci * features that are not yet implemented there, for example, WTX cmd handling. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_cienum st95hf_cmd_list { 10962306a36Sopenharmony_ci CMD_ECHO, 11062306a36Sopenharmony_ci CMD_ISO14443A_CONFIG, 11162306a36Sopenharmony_ci CMD_ISO14443A_DEMOGAIN, 11262306a36Sopenharmony_ci CMD_ISO14443B_DEMOGAIN, 11362306a36Sopenharmony_ci CMD_ISO14443A_PROTOCOL_SELECT, 11462306a36Sopenharmony_ci CMD_ISO14443B_PROTOCOL_SELECT, 11562306a36Sopenharmony_ci CMD_WTX_RESPONSE, 11662306a36Sopenharmony_ci CMD_FIELD_OFF, 11762306a36Sopenharmony_ci CMD_ISO15693_PROTOCOL_SELECT, 11862306a36Sopenharmony_ci}; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic const struct cmd cmd_array[] = { 12162306a36Sopenharmony_ci [CMD_ECHO] = { 12262306a36Sopenharmony_ci .cmd_len = 0x2, 12362306a36Sopenharmony_ci .cmd_id = ECHO_CMD, 12462306a36Sopenharmony_ci .no_cmd_params = 0, 12562306a36Sopenharmony_ci .req = SYNC, 12662306a36Sopenharmony_ci }, 12762306a36Sopenharmony_ci [CMD_ISO14443A_CONFIG] = { 12862306a36Sopenharmony_ci .cmd_len = 0x7, 12962306a36Sopenharmony_ci .cmd_id = WRITE_REGISTER_CMD, 13062306a36Sopenharmony_ci .no_cmd_params = 0x4, 13162306a36Sopenharmony_ci .cmd_params = {0x3A, 0x00, 0x5A, 0x04}, 13262306a36Sopenharmony_ci .req = SYNC, 13362306a36Sopenharmony_ci }, 13462306a36Sopenharmony_ci [CMD_ISO14443A_DEMOGAIN] = { 13562306a36Sopenharmony_ci .cmd_len = 0x7, 13662306a36Sopenharmony_ci .cmd_id = WRITE_REGISTER_CMD, 13762306a36Sopenharmony_ci .no_cmd_params = 0x4, 13862306a36Sopenharmony_ci .cmd_params = {0x68, 0x01, 0x01, 0xDF}, 13962306a36Sopenharmony_ci .req = SYNC, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci [CMD_ISO14443B_DEMOGAIN] = { 14262306a36Sopenharmony_ci .cmd_len = 0x7, 14362306a36Sopenharmony_ci .cmd_id = WRITE_REGISTER_CMD, 14462306a36Sopenharmony_ci .no_cmd_params = 0x4, 14562306a36Sopenharmony_ci .cmd_params = {0x68, 0x01, 0x01, 0x51}, 14662306a36Sopenharmony_ci .req = SYNC, 14762306a36Sopenharmony_ci }, 14862306a36Sopenharmony_ci [CMD_ISO14443A_PROTOCOL_SELECT] = { 14962306a36Sopenharmony_ci .cmd_len = 0x7, 15062306a36Sopenharmony_ci .cmd_id = PROTOCOL_SELECT_CMD, 15162306a36Sopenharmony_ci .no_cmd_params = 0x4, 15262306a36Sopenharmony_ci .cmd_params = {ISO14443A_PROTOCOL_CODE, 0x00, 0x01, 0xA0}, 15362306a36Sopenharmony_ci .req = SYNC, 15462306a36Sopenharmony_ci }, 15562306a36Sopenharmony_ci [CMD_ISO14443B_PROTOCOL_SELECT] = { 15662306a36Sopenharmony_ci .cmd_len = 0x7, 15762306a36Sopenharmony_ci .cmd_id = PROTOCOL_SELECT_CMD, 15862306a36Sopenharmony_ci .no_cmd_params = 0x4, 15962306a36Sopenharmony_ci .cmd_params = {ISO14443B_PROTOCOL_CODE, 0x01, 0x03, 0xFF}, 16062306a36Sopenharmony_ci .req = SYNC, 16162306a36Sopenharmony_ci }, 16262306a36Sopenharmony_ci [CMD_WTX_RESPONSE] = { 16362306a36Sopenharmony_ci .cmd_len = 0x6, 16462306a36Sopenharmony_ci .cmd_id = SEND_RECEIVE_CMD, 16562306a36Sopenharmony_ci .no_cmd_params = 0x3, 16662306a36Sopenharmony_ci .cmd_params = {0xF2, 0x00, TRFLAG_NFCA_STD_FRAME_CRC}, 16762306a36Sopenharmony_ci .req = ASYNC, 16862306a36Sopenharmony_ci }, 16962306a36Sopenharmony_ci [CMD_FIELD_OFF] = { 17062306a36Sopenharmony_ci .cmd_len = 0x5, 17162306a36Sopenharmony_ci .cmd_id = PROTOCOL_SELECT_CMD, 17262306a36Sopenharmony_ci .no_cmd_params = 0x2, 17362306a36Sopenharmony_ci .cmd_params = {0x0, 0x0}, 17462306a36Sopenharmony_ci .req = SYNC, 17562306a36Sopenharmony_ci }, 17662306a36Sopenharmony_ci [CMD_ISO15693_PROTOCOL_SELECT] = { 17762306a36Sopenharmony_ci .cmd_len = 0x5, 17862306a36Sopenharmony_ci .cmd_id = PROTOCOL_SELECT_CMD, 17962306a36Sopenharmony_ci .no_cmd_params = 0x2, 18062306a36Sopenharmony_ci .cmd_params = {ISO15693_PROTOCOL_CODE, 0x0D}, 18162306a36Sopenharmony_ci .req = SYNC, 18262306a36Sopenharmony_ci }, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/* st95_digital_cmd_complete_arg stores client context */ 18662306a36Sopenharmony_cistruct st95_digital_cmd_complete_arg { 18762306a36Sopenharmony_ci struct sk_buff *skb_resp; 18862306a36Sopenharmony_ci nfc_digital_cmd_complete_t complete_cb; 18962306a36Sopenharmony_ci void *cb_usrarg; 19062306a36Sopenharmony_ci bool rats; 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * structure containing ST95HF driver specific data. 19562306a36Sopenharmony_ci * @spicontext: structure containing information required 19662306a36Sopenharmony_ci * for spi communication between st95hf and host. 19762306a36Sopenharmony_ci * @ddev: nfc digital device object. 19862306a36Sopenharmony_ci * @nfcdev: nfc device object. 19962306a36Sopenharmony_ci * @enable_gpio: gpio used to enable st95hf transceiver. 20062306a36Sopenharmony_ci * @complete_cb_arg: structure to store various context information 20162306a36Sopenharmony_ci * that is passed from nfc requesting thread to the threaded ISR. 20262306a36Sopenharmony_ci * @st95hf_supply: regulator "consumer" for NFC device. 20362306a36Sopenharmony_ci * @sendrcv_trflag: last byte of frame send by sendrecv command 20462306a36Sopenharmony_ci * of st95hf. This byte contains transmission flag info. 20562306a36Sopenharmony_ci * @exchange_lock: semaphore used for signaling the st95hf_remove 20662306a36Sopenharmony_ci * function that the last outstanding async nfc request is finished. 20762306a36Sopenharmony_ci * @rm_lock: mutex for ensuring safe access of nfc digital object 20862306a36Sopenharmony_ci * from threaded ISR. Usage of this mutex avoids any race between 20962306a36Sopenharmony_ci * deletion of the object from st95hf_remove() and its access from 21062306a36Sopenharmony_ci * the threaded ISR. 21162306a36Sopenharmony_ci * @nfcdev_free: flag to have the state of nfc device object. 21262306a36Sopenharmony_ci * [alive | died] 21362306a36Sopenharmony_ci * @current_protocol: current nfc protocol. 21462306a36Sopenharmony_ci * @current_rf_tech: current rf technology. 21562306a36Sopenharmony_ci * @fwi: frame waiting index, received in reply of RATS according to 21662306a36Sopenharmony_ci * digital protocol. 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cistruct st95hf_context { 21962306a36Sopenharmony_ci struct st95hf_spi_context spicontext; 22062306a36Sopenharmony_ci struct nfc_digital_dev *ddev; 22162306a36Sopenharmony_ci struct nfc_dev *nfcdev; 22262306a36Sopenharmony_ci unsigned int enable_gpio; 22362306a36Sopenharmony_ci struct st95_digital_cmd_complete_arg complete_cb_arg; 22462306a36Sopenharmony_ci struct regulator *st95hf_supply; 22562306a36Sopenharmony_ci unsigned char sendrcv_trflag; 22662306a36Sopenharmony_ci struct semaphore exchange_lock; 22762306a36Sopenharmony_ci struct mutex rm_lock; 22862306a36Sopenharmony_ci bool nfcdev_free; 22962306a36Sopenharmony_ci u8 current_protocol; 23062306a36Sopenharmony_ci u8 current_rf_tech; 23162306a36Sopenharmony_ci int fwi; 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* 23562306a36Sopenharmony_ci * st95hf_send_recv_cmd() is for sending commands to ST95HF 23662306a36Sopenharmony_ci * that are described in the cmd_array[]. It can optionally 23762306a36Sopenharmony_ci * receive the response if the cmd request is of type 23862306a36Sopenharmony_ci * SYNC. For that to happen caller must pass true to recv_res. 23962306a36Sopenharmony_ci * For ASYNC request, recv_res is ignored and the 24062306a36Sopenharmony_ci * function will never try to receive the response on behalf 24162306a36Sopenharmony_ci * of the caller. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic int st95hf_send_recv_cmd(struct st95hf_context *st95context, 24462306a36Sopenharmony_ci enum st95hf_cmd_list cmd, 24562306a36Sopenharmony_ci int no_modif, 24662306a36Sopenharmony_ci struct param_list *list_array, 24762306a36Sopenharmony_ci bool recv_res) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci unsigned char spi_cmd_buffer[MAX_CMD_LEN]; 25062306a36Sopenharmony_ci int i, ret; 25162306a36Sopenharmony_ci struct device *dev = &st95context->spicontext.spidev->dev; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (cmd_array[cmd].cmd_len > MAX_CMD_LEN) 25462306a36Sopenharmony_ci return -EINVAL; 25562306a36Sopenharmony_ci if (cmd_array[cmd].no_cmd_params < no_modif) 25662306a36Sopenharmony_ci return -EINVAL; 25762306a36Sopenharmony_ci if (no_modif && !list_array) 25862306a36Sopenharmony_ci return -EINVAL; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci spi_cmd_buffer[0] = ST95HF_COMMAND_SEND; 26162306a36Sopenharmony_ci spi_cmd_buffer[1] = cmd_array[cmd].cmd_id; 26262306a36Sopenharmony_ci spi_cmd_buffer[2] = cmd_array[cmd].no_cmd_params; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci memcpy(&spi_cmd_buffer[3], cmd_array[cmd].cmd_params, 26562306a36Sopenharmony_ci spi_cmd_buffer[2]); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci for (i = 0; i < no_modif; i++) { 26862306a36Sopenharmony_ci if (list_array[i].param_offset >= cmd_array[cmd].no_cmd_params) 26962306a36Sopenharmony_ci return -EINVAL; 27062306a36Sopenharmony_ci spi_cmd_buffer[3 + list_array[i].param_offset] = 27162306a36Sopenharmony_ci list_array[i].new_param_val; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ret = st95hf_spi_send(&st95context->spicontext, 27562306a36Sopenharmony_ci spi_cmd_buffer, 27662306a36Sopenharmony_ci cmd_array[cmd].cmd_len, 27762306a36Sopenharmony_ci cmd_array[cmd].req); 27862306a36Sopenharmony_ci if (ret) { 27962306a36Sopenharmony_ci dev_err(dev, "st95hf_spi_send failed with error %d\n", ret); 28062306a36Sopenharmony_ci return ret; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (cmd_array[cmd].req == SYNC && recv_res) { 28462306a36Sopenharmony_ci unsigned char st95hf_response_arr[2]; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ret = st95hf_spi_recv_response(&st95context->spicontext, 28762306a36Sopenharmony_ci st95hf_response_arr); 28862306a36Sopenharmony_ci if (ret < 0) { 28962306a36Sopenharmony_ci dev_err(dev, "spi error from st95hf_spi_recv_response(), err = 0x%x\n", 29062306a36Sopenharmony_ci ret); 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci if (st95hf_response_arr[0]) { 29562306a36Sopenharmony_ci dev_err(dev, "st95hf error from st95hf_spi_recv_response(), err = 0x%x\n", 29662306a36Sopenharmony_ci st95hf_response_arr[0]); 29762306a36Sopenharmony_ci return -EIO; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int st95hf_echo_command(struct st95hf_context *st95context) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci int result = 0; 30762306a36Sopenharmony_ci unsigned char echo_response; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci result = st95hf_send_recv_cmd(st95context, CMD_ECHO, 0, NULL, false); 31062306a36Sopenharmony_ci if (result) 31162306a36Sopenharmony_ci return result; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* If control reached here, response can be taken */ 31462306a36Sopenharmony_ci result = st95hf_spi_recv_echo_res(&st95context->spicontext, 31562306a36Sopenharmony_ci &echo_response); 31662306a36Sopenharmony_ci if (result) { 31762306a36Sopenharmony_ci dev_err(&st95context->spicontext.spidev->dev, 31862306a36Sopenharmony_ci "err: echo response receive error = 0x%x\n", result); 31962306a36Sopenharmony_ci return result; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (echo_response == ECHORESPONSE) 32362306a36Sopenharmony_ci return 0; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci dev_err(&st95context->spicontext.spidev->dev, "err: echo res is 0x%x\n", 32662306a36Sopenharmony_ci echo_response); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return -EIO; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int secondary_configuration_type4a(struct st95hf_context *stcontext) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int result = 0; 33462306a36Sopenharmony_ci struct device *dev = &stcontext->nfcdev->dev; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* 14443A config setting after select protocol */ 33762306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 33862306a36Sopenharmony_ci CMD_ISO14443A_CONFIG, 33962306a36Sopenharmony_ci 0, 34062306a36Sopenharmony_ci NULL, 34162306a36Sopenharmony_ci true); 34262306a36Sopenharmony_ci if (result) { 34362306a36Sopenharmony_ci dev_err(dev, "type a config cmd, err = 0x%x\n", result); 34462306a36Sopenharmony_ci return result; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* 14443A demo gain setting */ 34862306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 34962306a36Sopenharmony_ci CMD_ISO14443A_DEMOGAIN, 35062306a36Sopenharmony_ci 0, 35162306a36Sopenharmony_ci NULL, 35262306a36Sopenharmony_ci true); 35362306a36Sopenharmony_ci if (result) 35462306a36Sopenharmony_ci dev_err(dev, "type a demogain cmd, err = 0x%x\n", result); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return result; 35762306a36Sopenharmony_ci} 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic int secondary_configuration_type4b(struct st95hf_context *stcontext) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci int result = 0; 36262306a36Sopenharmony_ci struct device *dev = &stcontext->nfcdev->dev; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 36562306a36Sopenharmony_ci CMD_ISO14443B_DEMOGAIN, 36662306a36Sopenharmony_ci 0, 36762306a36Sopenharmony_ci NULL, 36862306a36Sopenharmony_ci true); 36962306a36Sopenharmony_ci if (result) 37062306a36Sopenharmony_ci dev_err(dev, "type b demogain cmd, err = 0x%x\n", result); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return result; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic int st95hf_select_protocol(struct st95hf_context *stcontext, int type) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci int result = 0; 37862306a36Sopenharmony_ci struct device *dev; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci dev = &stcontext->nfcdev->dev; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci switch (type) { 38362306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 38462306a36Sopenharmony_ci stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106A; 38562306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 38662306a36Sopenharmony_ci CMD_ISO14443A_PROTOCOL_SELECT, 38762306a36Sopenharmony_ci 0, 38862306a36Sopenharmony_ci NULL, 38962306a36Sopenharmony_ci true); 39062306a36Sopenharmony_ci if (result) { 39162306a36Sopenharmony_ci dev_err(dev, "protocol sel, err = 0x%x\n", 39262306a36Sopenharmony_ci result); 39362306a36Sopenharmony_ci return result; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* secondary config. for 14443Type 4A after protocol select */ 39762306a36Sopenharmony_ci result = secondary_configuration_type4a(stcontext); 39862306a36Sopenharmony_ci if (result) { 39962306a36Sopenharmony_ci dev_err(dev, "type a secondary config, err = 0x%x\n", 40062306a36Sopenharmony_ci result); 40162306a36Sopenharmony_ci return result; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106B: 40562306a36Sopenharmony_ci stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106B; 40662306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 40762306a36Sopenharmony_ci CMD_ISO14443B_PROTOCOL_SELECT, 40862306a36Sopenharmony_ci 0, 40962306a36Sopenharmony_ci NULL, 41062306a36Sopenharmony_ci true); 41162306a36Sopenharmony_ci if (result) { 41262306a36Sopenharmony_ci dev_err(dev, "protocol sel send, err = 0x%x\n", 41362306a36Sopenharmony_ci result); 41462306a36Sopenharmony_ci return result; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * delay of 5-6 ms is required after select protocol 41962306a36Sopenharmony_ci * command in case of ISO14443 Type B 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci usleep_range(50000, 60000); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* secondary config. for 14443Type 4B after protocol select */ 42462306a36Sopenharmony_ci result = secondary_configuration_type4b(stcontext); 42562306a36Sopenharmony_ci if (result) { 42662306a36Sopenharmony_ci dev_err(dev, "type b secondary config, err = 0x%x\n", 42762306a36Sopenharmony_ci result); 42862306a36Sopenharmony_ci return result; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci break; 43162306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_ISO15693: 43262306a36Sopenharmony_ci stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_ISO15693; 43362306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 43462306a36Sopenharmony_ci CMD_ISO15693_PROTOCOL_SELECT, 43562306a36Sopenharmony_ci 0, 43662306a36Sopenharmony_ci NULL, 43762306a36Sopenharmony_ci true); 43862306a36Sopenharmony_ci if (result) { 43962306a36Sopenharmony_ci dev_err(dev, "protocol sel send, err = 0x%x\n", 44062306a36Sopenharmony_ci result); 44162306a36Sopenharmony_ci return result; 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci default: 44562306a36Sopenharmony_ci return -EINVAL; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void st95hf_send_st95enable_negativepulse(struct st95hf_context *st95con) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci /* First make irq_in pin high */ 45462306a36Sopenharmony_ci gpio_set_value(st95con->enable_gpio, HIGH); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* wait for 1 milisecond */ 45762306a36Sopenharmony_ci usleep_range(1000, 2000); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Make irq_in pin low */ 46062306a36Sopenharmony_ci gpio_set_value(st95con->enable_gpio, LOW); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* wait for minimum interrupt pulse to make st95 active */ 46362306a36Sopenharmony_ci usleep_range(1000, 2000); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* At end make it high */ 46662306a36Sopenharmony_ci gpio_set_value(st95con->enable_gpio, HIGH); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/* 47062306a36Sopenharmony_ci * Send a reset sequence over SPI bus (Reset command + wait 3ms + 47162306a36Sopenharmony_ci * negative pulse on st95hf enable gpio 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_cistatic int st95hf_send_spi_reset_sequence(struct st95hf_context *st95context) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci int result = 0; 47662306a36Sopenharmony_ci unsigned char reset_cmd = ST95HF_COMMAND_RESET; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci result = st95hf_spi_send(&st95context->spicontext, 47962306a36Sopenharmony_ci &reset_cmd, 48062306a36Sopenharmony_ci ST95HF_RESET_CMD_LEN, 48162306a36Sopenharmony_ci ASYNC); 48262306a36Sopenharmony_ci if (result) { 48362306a36Sopenharmony_ci dev_err(&st95context->spicontext.spidev->dev, 48462306a36Sopenharmony_ci "spi reset sequence cmd error = %d", result); 48562306a36Sopenharmony_ci return result; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* wait for 3 milisecond to complete the controller reset process */ 48962306a36Sopenharmony_ci usleep_range(3000, 4000); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* send negative pulse to make st95hf active */ 49262306a36Sopenharmony_ci st95hf_send_st95enable_negativepulse(st95context); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* wait for 10 milisecond : HFO setup time */ 49562306a36Sopenharmony_ci usleep_range(10000, 20000); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return result; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int st95hf_por_sequence(struct st95hf_context *st95context) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci int nth_attempt = 1; 50362306a36Sopenharmony_ci int result; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci st95hf_send_st95enable_negativepulse(st95context); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci usleep_range(5000, 6000); 50862306a36Sopenharmony_ci do { 50962306a36Sopenharmony_ci /* send an ECHO command and checks ST95HF response */ 51062306a36Sopenharmony_ci result = st95hf_echo_command(st95context); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci dev_dbg(&st95context->spicontext.spidev->dev, 51362306a36Sopenharmony_ci "response from echo function = 0x%x, attempt = %d\n", 51462306a36Sopenharmony_ci result, nth_attempt); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (!result) 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* send an pulse on IRQ in case of the chip is on sleep state */ 52062306a36Sopenharmony_ci if (nth_attempt == 2) 52162306a36Sopenharmony_ci st95hf_send_st95enable_negativepulse(st95context); 52262306a36Sopenharmony_ci else 52362306a36Sopenharmony_ci st95hf_send_spi_reset_sequence(st95context); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* delay of 50 milisecond */ 52662306a36Sopenharmony_ci usleep_range(50000, 51000); 52762306a36Sopenharmony_ci } while (nth_attempt++ < 3); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci return -ETIMEDOUT; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cistatic int iso14443_config_fdt(struct st95hf_context *st95context, int wtxm) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci int result = 0; 53562306a36Sopenharmony_ci struct device *dev = &st95context->spicontext.spidev->dev; 53662306a36Sopenharmony_ci struct nfc_digital_dev *nfcddev = st95context->ddev; 53762306a36Sopenharmony_ci unsigned char pp_typeb; 53862306a36Sopenharmony_ci struct param_list new_params[2]; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci pp_typeb = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[2]; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 && 54362306a36Sopenharmony_ci st95context->fwi < 4) 54462306a36Sopenharmony_ci st95context->fwi = 4; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci new_params[0].param_offset = 2; 54762306a36Sopenharmony_ci if (nfcddev->curr_protocol == NFC_PROTO_ISO14443) 54862306a36Sopenharmony_ci new_params[0].new_param_val = st95context->fwi; 54962306a36Sopenharmony_ci else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B) 55062306a36Sopenharmony_ci new_params[0].new_param_val = pp_typeb; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci new_params[1].param_offset = 3; 55362306a36Sopenharmony_ci new_params[1].new_param_val = wtxm; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci switch (nfcddev->curr_protocol) { 55662306a36Sopenharmony_ci case NFC_PROTO_ISO14443: 55762306a36Sopenharmony_ci result = st95hf_send_recv_cmd(st95context, 55862306a36Sopenharmony_ci CMD_ISO14443A_PROTOCOL_SELECT, 55962306a36Sopenharmony_ci 2, 56062306a36Sopenharmony_ci new_params, 56162306a36Sopenharmony_ci true); 56262306a36Sopenharmony_ci if (result) { 56362306a36Sopenharmony_ci dev_err(dev, "WTX type a sel proto, err = 0x%x\n", 56462306a36Sopenharmony_ci result); 56562306a36Sopenharmony_ci return result; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* secondary config. for 14443Type 4A after protocol select */ 56962306a36Sopenharmony_ci result = secondary_configuration_type4a(st95context); 57062306a36Sopenharmony_ci if (result) { 57162306a36Sopenharmony_ci dev_err(dev, "WTX type a second. config, err = 0x%x\n", 57262306a36Sopenharmony_ci result); 57362306a36Sopenharmony_ci return result; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci case NFC_PROTO_ISO14443_B: 57762306a36Sopenharmony_ci result = st95hf_send_recv_cmd(st95context, 57862306a36Sopenharmony_ci CMD_ISO14443B_PROTOCOL_SELECT, 57962306a36Sopenharmony_ci 2, 58062306a36Sopenharmony_ci new_params, 58162306a36Sopenharmony_ci true); 58262306a36Sopenharmony_ci if (result) { 58362306a36Sopenharmony_ci dev_err(dev, "WTX type b sel proto, err = 0x%x\n", 58462306a36Sopenharmony_ci result); 58562306a36Sopenharmony_ci return result; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* secondary config. for 14443Type 4B after protocol select */ 58962306a36Sopenharmony_ci result = secondary_configuration_type4b(st95context); 59062306a36Sopenharmony_ci if (result) { 59162306a36Sopenharmony_ci dev_err(dev, "WTX type b second. config, err = 0x%x\n", 59262306a36Sopenharmony_ci result); 59362306a36Sopenharmony_ci return result; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci default: 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return 0; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic int st95hf_handle_wtx(struct st95hf_context *stcontext, 60462306a36Sopenharmony_ci bool new_wtx, 60562306a36Sopenharmony_ci int wtx_val) 60662306a36Sopenharmony_ci{ 60762306a36Sopenharmony_ci int result = 0; 60862306a36Sopenharmony_ci unsigned char val_mm = 0; 60962306a36Sopenharmony_ci struct param_list new_params[1]; 61062306a36Sopenharmony_ci struct nfc_digital_dev *nfcddev = stcontext->ddev; 61162306a36Sopenharmony_ci struct device *dev = &stcontext->nfcdev->dev; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (new_wtx) { 61462306a36Sopenharmony_ci result = iso14443_config_fdt(stcontext, wtx_val & 0x3f); 61562306a36Sopenharmony_ci if (result) { 61662306a36Sopenharmony_ci dev_err(dev, "Config. setting error on WTX req, err = 0x%x\n", 61762306a36Sopenharmony_ci result); 61862306a36Sopenharmony_ci return result; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* Send response of wtx with ASYNC as no response expected */ 62262306a36Sopenharmony_ci new_params[0].param_offset = 1; 62362306a36Sopenharmony_ci new_params[0].new_param_val = wtx_val; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci result = st95hf_send_recv_cmd(stcontext, 62662306a36Sopenharmony_ci CMD_WTX_RESPONSE, 62762306a36Sopenharmony_ci 1, 62862306a36Sopenharmony_ci new_params, 62962306a36Sopenharmony_ci false); 63062306a36Sopenharmony_ci if (result) 63162306a36Sopenharmony_ci dev_err(dev, "WTX response send, err = 0x%x\n", result); 63262306a36Sopenharmony_ci return result; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci /* if no new wtx, cofigure with default values */ 63662306a36Sopenharmony_ci if (nfcddev->curr_protocol == NFC_PROTO_ISO14443) 63762306a36Sopenharmony_ci val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3]; 63862306a36Sopenharmony_ci else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B) 63962306a36Sopenharmony_ci val_mm = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[3]; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci result = iso14443_config_fdt(stcontext, val_mm); 64262306a36Sopenharmony_ci if (result) 64362306a36Sopenharmony_ci dev_err(dev, "Default config. setting error after WTX processing, err = 0x%x\n", 64462306a36Sopenharmony_ci result); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return result; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int st95hf_error_handling(struct st95hf_context *stcontext, 65062306a36Sopenharmony_ci struct sk_buff *skb_resp, 65162306a36Sopenharmony_ci int res_len) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci int result = 0; 65462306a36Sopenharmony_ci unsigned char error_byte; 65562306a36Sopenharmony_ci struct device *dev = &stcontext->nfcdev->dev; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* First check ST95HF specific error */ 65862306a36Sopenharmony_ci if (skb_resp->data[0] & ST95HF_ERR_MASK) { 65962306a36Sopenharmony_ci if (skb_resp->data[0] == ST95HF_TIMEOUT_ERROR) 66062306a36Sopenharmony_ci result = -ETIMEDOUT; 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci result = -EIO; 66362306a36Sopenharmony_ci return result; 66462306a36Sopenharmony_ci } 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci /* Check for CRC err only if CRC is present in the tag response */ 66762306a36Sopenharmony_ci switch (stcontext->current_rf_tech) { 66862306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 66962306a36Sopenharmony_ci if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC) { 67062306a36Sopenharmony_ci error_byte = skb_resp->data[res_len - 3]; 67162306a36Sopenharmony_ci if (error_byte & ST95HF_NFCA_CRC_ERR_MASK) { 67262306a36Sopenharmony_ci /* CRC error occurred */ 67362306a36Sopenharmony_ci dev_err(dev, "CRC error, byte received = 0x%x\n", 67462306a36Sopenharmony_ci error_byte); 67562306a36Sopenharmony_ci result = -EIO; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106B: 68062306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_ISO15693: 68162306a36Sopenharmony_ci error_byte = skb_resp->data[res_len - 1]; 68262306a36Sopenharmony_ci if (error_byte & ST95HF_NFCB_CRC_ERR_MASK) { 68362306a36Sopenharmony_ci /* CRC error occurred */ 68462306a36Sopenharmony_ci dev_err(dev, "CRC error, byte received = 0x%x\n", 68562306a36Sopenharmony_ci error_byte); 68662306a36Sopenharmony_ci result = -EIO; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return result; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int st95hf_response_handler(struct st95hf_context *stcontext, 69562306a36Sopenharmony_ci struct sk_buff *skb_resp, 69662306a36Sopenharmony_ci int res_len) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci int result = 0; 69962306a36Sopenharmony_ci int skb_len; 70062306a36Sopenharmony_ci unsigned char val_mm; 70162306a36Sopenharmony_ci struct nfc_digital_dev *nfcddev = stcontext->ddev; 70262306a36Sopenharmony_ci struct device *dev = &stcontext->nfcdev->dev; 70362306a36Sopenharmony_ci struct st95_digital_cmd_complete_arg *cb_arg; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci cb_arg = &stcontext->complete_cb_arg; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Process the response */ 70862306a36Sopenharmony_ci skb_put(skb_resp, res_len); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* Remove st95 header */ 71162306a36Sopenharmony_ci skb_pull(skb_resp, 2); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci skb_len = skb_resp->len; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* check if it is case of RATS request reply & FWI is present */ 71662306a36Sopenharmony_ci if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 && cb_arg->rats && 71762306a36Sopenharmony_ci (skb_resp->data[1] & RATS_TB1_PRESENT_MASK)) { 71862306a36Sopenharmony_ci if (skb_resp->data[1] & RATS_TA1_PRESENT_MASK) 71962306a36Sopenharmony_ci stcontext->fwi = 72062306a36Sopenharmony_ci (skb_resp->data[3] & TB1_FWI_MASK) >> 4; 72162306a36Sopenharmony_ci else 72262306a36Sopenharmony_ci stcontext->fwi = 72362306a36Sopenharmony_ci (skb_resp->data[2] & TB1_FWI_MASK) >> 4; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3]; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci result = iso14443_config_fdt(stcontext, val_mm); 72862306a36Sopenharmony_ci if (result) { 72962306a36Sopenharmony_ci dev_err(dev, "error in config_fdt to handle fwi of ATS, error=%d\n", 73062306a36Sopenharmony_ci result); 73162306a36Sopenharmony_ci return result; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci cb_arg->rats = false; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Remove CRC bytes only if received frames data has an eod (CRC) */ 73762306a36Sopenharmony_ci switch (stcontext->current_rf_tech) { 73862306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 73962306a36Sopenharmony_ci if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC) 74062306a36Sopenharmony_ci skb_trim(skb_resp, (skb_len - 5)); 74162306a36Sopenharmony_ci else 74262306a36Sopenharmony_ci skb_trim(skb_resp, (skb_len - 3)); 74362306a36Sopenharmony_ci break; 74462306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106B: 74562306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_ISO15693: 74662306a36Sopenharmony_ci skb_trim(skb_resp, (skb_len - 3)); 74762306a36Sopenharmony_ci break; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return result; 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic irqreturn_t st95hf_irq_handler(int irq, void *st95hfcontext) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct st95hf_context *stcontext = 75662306a36Sopenharmony_ci (struct st95hf_context *)st95hfcontext; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (stcontext->spicontext.req_issync) { 75962306a36Sopenharmony_ci complete(&stcontext->spicontext.done); 76062306a36Sopenharmony_ci stcontext->spicontext.req_issync = false; 76162306a36Sopenharmony_ci return IRQ_HANDLED; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic irqreturn_t st95hf_irq_thread_handler(int irq, void *st95hfcontext) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci int result = 0; 77062306a36Sopenharmony_ci int res_len; 77162306a36Sopenharmony_ci static bool wtx; 77262306a36Sopenharmony_ci struct device *spidevice; 77362306a36Sopenharmony_ci struct sk_buff *skb_resp; 77462306a36Sopenharmony_ci struct st95hf_context *stcontext = 77562306a36Sopenharmony_ci (struct st95hf_context *)st95hfcontext; 77662306a36Sopenharmony_ci struct st95_digital_cmd_complete_arg *cb_arg; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci spidevice = &stcontext->spicontext.spidev->dev; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci /* 78162306a36Sopenharmony_ci * check semaphore, if not down() already, then we don't 78262306a36Sopenharmony_ci * know in which context the ISR is called and surely it 78362306a36Sopenharmony_ci * will be a bug. Note that down() of the semaphore is done 78462306a36Sopenharmony_ci * in the corresponding st95hf_in_send_cmd() and then 78562306a36Sopenharmony_ci * only this ISR should be called. ISR will up() the 78662306a36Sopenharmony_ci * semaphore before leaving. Hence when the ISR is called 78762306a36Sopenharmony_ci * the correct behaviour is down_trylock() should always 78862306a36Sopenharmony_ci * return 1 (indicating semaphore cant be taken and hence no 78962306a36Sopenharmony_ci * change in semaphore count). 79062306a36Sopenharmony_ci * If not, then we up() the semaphore and crash on 79162306a36Sopenharmony_ci * a BUG() ! 79262306a36Sopenharmony_ci */ 79362306a36Sopenharmony_ci if (!down_trylock(&stcontext->exchange_lock)) { 79462306a36Sopenharmony_ci up(&stcontext->exchange_lock); 79562306a36Sopenharmony_ci WARN(1, "unknown context in ST95HF ISR"); 79662306a36Sopenharmony_ci return IRQ_NONE; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci cb_arg = &stcontext->complete_cb_arg; 80062306a36Sopenharmony_ci skb_resp = cb_arg->skb_resp; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci mutex_lock(&stcontext->rm_lock); 80362306a36Sopenharmony_ci res_len = st95hf_spi_recv_response(&stcontext->spicontext, 80462306a36Sopenharmony_ci skb_resp->data); 80562306a36Sopenharmony_ci if (res_len < 0) { 80662306a36Sopenharmony_ci dev_err(spidevice, "TISR spi response err = 0x%x\n", res_len); 80762306a36Sopenharmony_ci result = res_len; 80862306a36Sopenharmony_ci goto end; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci /* if stcontext->nfcdev_free is true, it means remove already ran */ 81262306a36Sopenharmony_ci if (stcontext->nfcdev_free) { 81362306a36Sopenharmony_ci result = -ENODEV; 81462306a36Sopenharmony_ci goto end; 81562306a36Sopenharmony_ci } 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (skb_resp->data[2] == WTX_REQ_FROM_TAG) { 81862306a36Sopenharmony_ci /* Request for new FWT from tag */ 81962306a36Sopenharmony_ci result = st95hf_handle_wtx(stcontext, true, skb_resp->data[3]); 82062306a36Sopenharmony_ci if (result) 82162306a36Sopenharmony_ci goto end; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci wtx = true; 82462306a36Sopenharmony_ci mutex_unlock(&stcontext->rm_lock); 82562306a36Sopenharmony_ci return IRQ_HANDLED; 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci result = st95hf_error_handling(stcontext, skb_resp, res_len); 82962306a36Sopenharmony_ci if (result) 83062306a36Sopenharmony_ci goto end; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci result = st95hf_response_handler(stcontext, skb_resp, res_len); 83362306a36Sopenharmony_ci if (result) 83462306a36Sopenharmony_ci goto end; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * If select protocol is done on wtx req. do select protocol 83862306a36Sopenharmony_ci * again with default values 83962306a36Sopenharmony_ci */ 84062306a36Sopenharmony_ci if (wtx) { 84162306a36Sopenharmony_ci wtx = false; 84262306a36Sopenharmony_ci result = st95hf_handle_wtx(stcontext, false, 0); 84362306a36Sopenharmony_ci if (result) 84462306a36Sopenharmony_ci goto end; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* call digital layer callback */ 84862306a36Sopenharmony_ci cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* up the semaphore before returning */ 85162306a36Sopenharmony_ci up(&stcontext->exchange_lock); 85262306a36Sopenharmony_ci mutex_unlock(&stcontext->rm_lock); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci return IRQ_HANDLED; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ciend: 85762306a36Sopenharmony_ci kfree_skb(skb_resp); 85862306a36Sopenharmony_ci wtx = false; 85962306a36Sopenharmony_ci cb_arg->rats = false; 86062306a36Sopenharmony_ci skb_resp = ERR_PTR(result); 86162306a36Sopenharmony_ci /* call of callback with error */ 86262306a36Sopenharmony_ci cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp); 86362306a36Sopenharmony_ci /* up the semaphore before returning */ 86462306a36Sopenharmony_ci up(&stcontext->exchange_lock); 86562306a36Sopenharmony_ci mutex_unlock(&stcontext->rm_lock); 86662306a36Sopenharmony_ci return IRQ_HANDLED; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci/* NFC ops functions definition */ 87062306a36Sopenharmony_cistatic int st95hf_in_configure_hw(struct nfc_digital_dev *ddev, 87162306a36Sopenharmony_ci int type, 87262306a36Sopenharmony_ci int param) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (type == NFC_DIGITAL_CONFIG_RF_TECH) 87762306a36Sopenharmony_ci return st95hf_select_protocol(stcontext, param); 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (type == NFC_DIGITAL_CONFIG_FRAMING) { 88062306a36Sopenharmony_ci switch (param) { 88162306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCA_SHORT: 88262306a36Sopenharmony_ci stcontext->sendrcv_trflag = TRFLAG_NFCA_SHORT_FRAME; 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCA_STANDARD: 88562306a36Sopenharmony_ci stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME; 88662306a36Sopenharmony_ci break; 88762306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCA_T4T: 88862306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP: 88962306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A: 89062306a36Sopenharmony_ci stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME_CRC; 89162306a36Sopenharmony_ci break; 89262306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_NFCB: 89362306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY: 89462306a36Sopenharmony_ci case NFC_DIGITAL_FRAMING_ISO15693_T5T: 89562306a36Sopenharmony_ci break; 89662306a36Sopenharmony_ci } 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci return 0; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int rf_off(struct st95hf_context *stcontext) 90362306a36Sopenharmony_ci{ 90462306a36Sopenharmony_ci int rc; 90562306a36Sopenharmony_ci struct device *dev; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci dev = &stcontext->nfcdev->dev; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci rc = st95hf_send_recv_cmd(stcontext, CMD_FIELD_OFF, 0, NULL, true); 91062306a36Sopenharmony_ci if (rc) 91162306a36Sopenharmony_ci dev_err(dev, "protocol sel send field off, err = 0x%x\n", rc); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return rc; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int st95hf_in_send_cmd(struct nfc_digital_dev *ddev, 91762306a36Sopenharmony_ci struct sk_buff *skb, 91862306a36Sopenharmony_ci u16 timeout, 91962306a36Sopenharmony_ci nfc_digital_cmd_complete_t cb, 92062306a36Sopenharmony_ci void *arg) 92162306a36Sopenharmony_ci{ 92262306a36Sopenharmony_ci struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev); 92362306a36Sopenharmony_ci int rc; 92462306a36Sopenharmony_ci struct sk_buff *skb_resp; 92562306a36Sopenharmony_ci int len_data_to_tag = 0; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci skb_resp = nfc_alloc_recv_skb(MAX_RESPONSE_BUFFER_SIZE, GFP_KERNEL); 92862306a36Sopenharmony_ci if (!skb_resp) 92962306a36Sopenharmony_ci return -ENOMEM; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci switch (stcontext->current_rf_tech) { 93262306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106A: 93362306a36Sopenharmony_ci len_data_to_tag = skb->len + 1; 93462306a36Sopenharmony_ci skb_put_u8(skb, stcontext->sendrcv_trflag); 93562306a36Sopenharmony_ci break; 93662306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_106B: 93762306a36Sopenharmony_ci case NFC_DIGITAL_RF_TECH_ISO15693: 93862306a36Sopenharmony_ci len_data_to_tag = skb->len; 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci default: 94162306a36Sopenharmony_ci rc = -EINVAL; 94262306a36Sopenharmony_ci goto free_skb_resp; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci skb_push(skb, 3); 94662306a36Sopenharmony_ci skb->data[0] = ST95HF_COMMAND_SEND; 94762306a36Sopenharmony_ci skb->data[1] = SEND_RECEIVE_CMD; 94862306a36Sopenharmony_ci skb->data[2] = len_data_to_tag; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci stcontext->complete_cb_arg.skb_resp = skb_resp; 95162306a36Sopenharmony_ci stcontext->complete_cb_arg.cb_usrarg = arg; 95262306a36Sopenharmony_ci stcontext->complete_cb_arg.complete_cb = cb; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci if ((skb->data[3] == ISO14443A_RATS_REQ) && 95562306a36Sopenharmony_ci ddev->curr_protocol == NFC_PROTO_ISO14443) 95662306a36Sopenharmony_ci stcontext->complete_cb_arg.rats = true; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* 95962306a36Sopenharmony_ci * down the semaphore to indicate to remove func that an 96062306a36Sopenharmony_ci * ISR is pending, note that it will not block here in any case. 96162306a36Sopenharmony_ci * If found blocked, it is a BUG! 96262306a36Sopenharmony_ci */ 96362306a36Sopenharmony_ci rc = down_killable(&stcontext->exchange_lock); 96462306a36Sopenharmony_ci if (rc) { 96562306a36Sopenharmony_ci WARN(1, "Semaphore is not found up in st95hf_in_send_cmd\n"); 96662306a36Sopenharmony_ci goto free_skb_resp; 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci rc = st95hf_spi_send(&stcontext->spicontext, skb->data, 97062306a36Sopenharmony_ci skb->len, 97162306a36Sopenharmony_ci ASYNC); 97262306a36Sopenharmony_ci if (rc) { 97362306a36Sopenharmony_ci dev_err(&stcontext->nfcdev->dev, 97462306a36Sopenharmony_ci "Error %d trying to perform data_exchange", rc); 97562306a36Sopenharmony_ci /* up the semaphore since ISR will never come in this case */ 97662306a36Sopenharmony_ci up(&stcontext->exchange_lock); 97762306a36Sopenharmony_ci goto free_skb_resp; 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci kfree_skb(skb); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci return rc; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cifree_skb_resp: 98562306a36Sopenharmony_ci kfree_skb(skb_resp); 98662306a36Sopenharmony_ci return rc; 98762306a36Sopenharmony_ci} 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci/* p2p will be supported in a later release ! */ 99062306a36Sopenharmony_cistatic int st95hf_tg_configure_hw(struct nfc_digital_dev *ddev, 99162306a36Sopenharmony_ci int type, 99262306a36Sopenharmony_ci int param) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci return 0; 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic int st95hf_tg_send_cmd(struct nfc_digital_dev *ddev, 99862306a36Sopenharmony_ci struct sk_buff *skb, 99962306a36Sopenharmony_ci u16 timeout, 100062306a36Sopenharmony_ci nfc_digital_cmd_complete_t cb, 100162306a36Sopenharmony_ci void *arg) 100262306a36Sopenharmony_ci{ 100362306a36Sopenharmony_ci return 0; 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_cistatic int st95hf_tg_listen(struct nfc_digital_dev *ddev, 100762306a36Sopenharmony_ci u16 timeout, 100862306a36Sopenharmony_ci nfc_digital_cmd_complete_t cb, 100962306a36Sopenharmony_ci void *arg) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci return 0; 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic int st95hf_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci return 0; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic int st95hf_switch_rf(struct nfc_digital_dev *ddev, bool on) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci u8 rf_tech; 102262306a36Sopenharmony_ci struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci rf_tech = ddev->curr_rf_tech; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (on) 102762306a36Sopenharmony_ci /* switch on RF field */ 102862306a36Sopenharmony_ci return st95hf_select_protocol(stcontext, rf_tech); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci /* switch OFF RF field */ 103162306a36Sopenharmony_ci return rf_off(stcontext); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci/* TODO st95hf_abort_cmd */ 103562306a36Sopenharmony_cistatic void st95hf_abort_cmd(struct nfc_digital_dev *ddev) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic const struct nfc_digital_ops st95hf_nfc_digital_ops = { 104062306a36Sopenharmony_ci .in_configure_hw = st95hf_in_configure_hw, 104162306a36Sopenharmony_ci .in_send_cmd = st95hf_in_send_cmd, 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci .tg_listen = st95hf_tg_listen, 104462306a36Sopenharmony_ci .tg_configure_hw = st95hf_tg_configure_hw, 104562306a36Sopenharmony_ci .tg_send_cmd = st95hf_tg_send_cmd, 104662306a36Sopenharmony_ci .tg_get_rf_tech = st95hf_tg_get_rf_tech, 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci .switch_rf = st95hf_switch_rf, 104962306a36Sopenharmony_ci .abort_cmd = st95hf_abort_cmd, 105062306a36Sopenharmony_ci}; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic const struct spi_device_id st95hf_id[] = { 105362306a36Sopenharmony_ci { "st95hf", 0 }, 105462306a36Sopenharmony_ci {} 105562306a36Sopenharmony_ci}; 105662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, st95hf_id); 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic const struct of_device_id st95hf_spi_of_match[] __maybe_unused = { 105962306a36Sopenharmony_ci { .compatible = "st,st95hf" }, 106062306a36Sopenharmony_ci {}, 106162306a36Sopenharmony_ci}; 106262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, st95hf_spi_of_match); 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int st95hf_probe(struct spi_device *nfc_spi_dev) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci int ret; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci struct st95hf_context *st95context; 106962306a36Sopenharmony_ci struct st95hf_spi_context *spicontext; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci nfc_info(&nfc_spi_dev->dev, "ST95HF driver probe called.\n"); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci st95context = devm_kzalloc(&nfc_spi_dev->dev, 107462306a36Sopenharmony_ci sizeof(struct st95hf_context), 107562306a36Sopenharmony_ci GFP_KERNEL); 107662306a36Sopenharmony_ci if (!st95context) 107762306a36Sopenharmony_ci return -ENOMEM; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci spicontext = &st95context->spicontext; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci spicontext->spidev = nfc_spi_dev; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci st95context->fwi = 108462306a36Sopenharmony_ci cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[2]; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (device_property_present(&nfc_spi_dev->dev, "st95hfvin")) { 108762306a36Sopenharmony_ci st95context->st95hf_supply = 108862306a36Sopenharmony_ci devm_regulator_get(&nfc_spi_dev->dev, 108962306a36Sopenharmony_ci "st95hfvin"); 109062306a36Sopenharmony_ci if (IS_ERR(st95context->st95hf_supply)) { 109162306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "failed to acquire regulator\n"); 109262306a36Sopenharmony_ci return PTR_ERR(st95context->st95hf_supply); 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci ret = regulator_enable(st95context->st95hf_supply); 109662306a36Sopenharmony_ci if (ret) { 109762306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "failed to enable regulator\n"); 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci init_completion(&spicontext->done); 110362306a36Sopenharmony_ci mutex_init(&spicontext->spi_lock); 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* 110662306a36Sopenharmony_ci * Store spicontext in spi device object for using it in 110762306a36Sopenharmony_ci * remove function 110862306a36Sopenharmony_ci */ 110962306a36Sopenharmony_ci dev_set_drvdata(&nfc_spi_dev->dev, spicontext); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci st95context->enable_gpio = 111262306a36Sopenharmony_ci of_get_named_gpio(nfc_spi_dev->dev.of_node, 111362306a36Sopenharmony_ci "enable-gpio", 111462306a36Sopenharmony_ci 0); 111562306a36Sopenharmony_ci if (!gpio_is_valid(st95context->enable_gpio)) { 111662306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "No valid enable gpio\n"); 111762306a36Sopenharmony_ci ret = st95context->enable_gpio; 111862306a36Sopenharmony_ci goto err_disable_regulator; 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci ret = devm_gpio_request_one(&nfc_spi_dev->dev, st95context->enable_gpio, 112262306a36Sopenharmony_ci GPIOF_DIR_OUT | GPIOF_INIT_HIGH, 112362306a36Sopenharmony_ci "enable_gpio"); 112462306a36Sopenharmony_ci if (ret) 112562306a36Sopenharmony_ci goto err_disable_regulator; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci if (nfc_spi_dev->irq > 0) { 112862306a36Sopenharmony_ci if (devm_request_threaded_irq(&nfc_spi_dev->dev, 112962306a36Sopenharmony_ci nfc_spi_dev->irq, 113062306a36Sopenharmony_ci st95hf_irq_handler, 113162306a36Sopenharmony_ci st95hf_irq_thread_handler, 113262306a36Sopenharmony_ci IRQF_TRIGGER_FALLING, 113362306a36Sopenharmony_ci "st95hf", 113462306a36Sopenharmony_ci (void *)st95context) < 0) { 113562306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "err: irq request for st95hf is failed\n"); 113662306a36Sopenharmony_ci ret = -EINVAL; 113762306a36Sopenharmony_ci goto err_disable_regulator; 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci } else { 114062306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "not a valid IRQ associated with ST95HF\n"); 114162306a36Sopenharmony_ci ret = -EINVAL; 114262306a36Sopenharmony_ci goto err_disable_regulator; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci /* 114662306a36Sopenharmony_ci * First reset SPI to handle warm reset of the system. 114762306a36Sopenharmony_ci * It will put the ST95HF device in Power ON state 114862306a36Sopenharmony_ci * which make the state of device identical to state 114962306a36Sopenharmony_ci * at the time of cold reset of the system. 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_ci ret = st95hf_send_spi_reset_sequence(st95context); 115262306a36Sopenharmony_ci if (ret) { 115362306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "err: spi_reset_sequence failed\n"); 115462306a36Sopenharmony_ci goto err_disable_regulator; 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci /* call PowerOnReset sequence of ST95hf to activate it */ 115862306a36Sopenharmony_ci ret = st95hf_por_sequence(st95context); 115962306a36Sopenharmony_ci if (ret) { 116062306a36Sopenharmony_ci dev_err(&nfc_spi_dev->dev, "err: por seq failed for st95hf\n"); 116162306a36Sopenharmony_ci goto err_disable_regulator; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* create NFC dev object and register with NFC Subsystem */ 116562306a36Sopenharmony_ci st95context->ddev = nfc_digital_allocate_device(&st95hf_nfc_digital_ops, 116662306a36Sopenharmony_ci ST95HF_SUPPORTED_PROT, 116762306a36Sopenharmony_ci ST95HF_CAPABILITIES, 116862306a36Sopenharmony_ci ST95HF_HEADROOM_LEN, 116962306a36Sopenharmony_ci ST95HF_TAILROOM_LEN); 117062306a36Sopenharmony_ci if (!st95context->ddev) { 117162306a36Sopenharmony_ci ret = -ENOMEM; 117262306a36Sopenharmony_ci goto err_disable_regulator; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci st95context->nfcdev = st95context->ddev->nfc_dev; 117662306a36Sopenharmony_ci nfc_digital_set_parent_dev(st95context->ddev, &nfc_spi_dev->dev); 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci ret = nfc_digital_register_device(st95context->ddev); 117962306a36Sopenharmony_ci if (ret) { 118062306a36Sopenharmony_ci dev_err(&st95context->nfcdev->dev, "st95hf registration failed\n"); 118162306a36Sopenharmony_ci goto err_free_digital_device; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* store st95context in nfc device object */ 118562306a36Sopenharmony_ci nfc_digital_set_drvdata(st95context->ddev, st95context); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci sema_init(&st95context->exchange_lock, 1); 118862306a36Sopenharmony_ci mutex_init(&st95context->rm_lock); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci return ret; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cierr_free_digital_device: 119362306a36Sopenharmony_ci nfc_digital_free_device(st95context->ddev); 119462306a36Sopenharmony_cierr_disable_regulator: 119562306a36Sopenharmony_ci if (st95context->st95hf_supply) 119662306a36Sopenharmony_ci regulator_disable(st95context->st95hf_supply); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci return ret; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic void st95hf_remove(struct spi_device *nfc_spi_dev) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci int result = 0; 120462306a36Sopenharmony_ci unsigned char reset_cmd = ST95HF_COMMAND_RESET; 120562306a36Sopenharmony_ci struct st95hf_spi_context *spictx = dev_get_drvdata(&nfc_spi_dev->dev); 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci struct st95hf_context *stcontext = container_of(spictx, 120862306a36Sopenharmony_ci struct st95hf_context, 120962306a36Sopenharmony_ci spicontext); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci mutex_lock(&stcontext->rm_lock); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci nfc_digital_unregister_device(stcontext->ddev); 121462306a36Sopenharmony_ci nfc_digital_free_device(stcontext->ddev); 121562306a36Sopenharmony_ci stcontext->nfcdev_free = true; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci mutex_unlock(&stcontext->rm_lock); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci /* if last in_send_cmd's ISR is pending, wait for it to finish */ 122062306a36Sopenharmony_ci result = down_killable(&stcontext->exchange_lock); 122162306a36Sopenharmony_ci if (result == -EINTR) 122262306a36Sopenharmony_ci dev_err(&spictx->spidev->dev, "sleep for semaphore interrupted by signal\n"); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci /* next reset the ST95HF controller */ 122562306a36Sopenharmony_ci result = st95hf_spi_send(&stcontext->spicontext, 122662306a36Sopenharmony_ci &reset_cmd, 122762306a36Sopenharmony_ci ST95HF_RESET_CMD_LEN, 122862306a36Sopenharmony_ci ASYNC); 122962306a36Sopenharmony_ci if (result) 123062306a36Sopenharmony_ci dev_err(&spictx->spidev->dev, 123162306a36Sopenharmony_ci "ST95HF reset failed in remove() err = %d\n", result); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* wait for 3 ms to complete the controller reset process */ 123462306a36Sopenharmony_ci usleep_range(3000, 4000); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* disable regulator */ 123762306a36Sopenharmony_ci if (stcontext->st95hf_supply) 123862306a36Sopenharmony_ci regulator_disable(stcontext->st95hf_supply); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci/* Register as SPI protocol driver */ 124262306a36Sopenharmony_cistatic struct spi_driver st95hf_driver = { 124362306a36Sopenharmony_ci .driver = { 124462306a36Sopenharmony_ci .name = "st95hf", 124562306a36Sopenharmony_ci .owner = THIS_MODULE, 124662306a36Sopenharmony_ci .of_match_table = of_match_ptr(st95hf_spi_of_match), 124762306a36Sopenharmony_ci }, 124862306a36Sopenharmony_ci .id_table = st95hf_id, 124962306a36Sopenharmony_ci .probe = st95hf_probe, 125062306a36Sopenharmony_ci .remove = st95hf_remove, 125162306a36Sopenharmony_ci}; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_cimodule_spi_driver(st95hf_driver); 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ciMODULE_AUTHOR("Shikha Singh <shikha.singh@st.com>"); 125662306a36Sopenharmony_ciMODULE_DESCRIPTION("ST NFC Transceiver ST95HF driver"); 125762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1258