12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274 |
- /*
- * --------------------------------------------------------------------
- * Driver for ST NFC Transceiver ST95HF
- * --------------------------------------------------------------------
- * Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
- #include <linux/err.h>
- #include <linux/gpio.h>
- #include <linux/init.h>
- #include <linux/interrupt.h>
- #include <linux/irq.h>
- #include <linux/module.h>
- #include <linux/netdevice.h>
- #include <linux/nfc.h>
- #include <linux/of_gpio.h>
- #include <linux/of.h>
- #include <linux/of_irq.h>
- #include <linux/property.h>
- #include <linux/regulator/consumer.h>
- #include <linux/wait.h>
- #include <net/nfc/digital.h>
- #include <net/nfc/nfc.h>
- #include "spi.h"
- /* supported protocols */
- #define ST95HF_SUPPORTED_PROT (NFC_PROTO_ISO14443_MASK | \
- NFC_PROTO_ISO14443_B_MASK | \
- NFC_PROTO_ISO15693_MASK)
- /* driver capabilities */
- #define ST95HF_CAPABILITIES NFC_DIGITAL_DRV_CAPS_IN_CRC
- /* Command Send Interface */
- /* ST95HF_COMMAND_SEND CMD Ids */
- #define ECHO_CMD 0x55
- #define WRITE_REGISTER_CMD 0x9
- #define PROTOCOL_SELECT_CMD 0x2
- #define SEND_RECEIVE_CMD 0x4
- /* Select protocol codes */
- #define ISO15693_PROTOCOL_CODE 0x1
- #define ISO14443A_PROTOCOL_CODE 0x2
- #define ISO14443B_PROTOCOL_CODE 0x3
- /*
- * head room len is 3
- * 1 byte for control byte
- * 1 byte for cmd
- * 1 byte for size
- */
- #define ST95HF_HEADROOM_LEN 3
- /*
- * tailroom is 1 for ISO14443A
- * and 0 for ISO14443B/ISO15693,
- * hence the max value 1 should be
- * taken.
- */
- #define ST95HF_TAILROOM_LEN 1
- /* Command Response interface */
- #define MAX_RESPONSE_BUFFER_SIZE 280
- #define ECHORESPONSE 0x55
- #define ST95HF_ERR_MASK 0xF
- #define ST95HF_TIMEOUT_ERROR 0x87
- #define ST95HF_NFCA_CRC_ERR_MASK 0x20
- #define ST95HF_NFCB_CRC_ERR_MASK 0x01
- /* ST95HF transmission flag values */
- #define TRFLAG_NFCA_SHORT_FRAME 0x07
- #define TRFLAG_NFCA_STD_FRAME 0x08
- #define TRFLAG_NFCA_STD_FRAME_CRC 0x28
- /* Misc defs */
- #define HIGH 1
- #define LOW 0
- #define ISO14443A_RATS_REQ 0xE0
- #define RATS_TB1_PRESENT_MASK 0x20
- #define RATS_TA1_PRESENT_MASK 0x10
- #define TB1_FWI_MASK 0xF0
- #define WTX_REQ_FROM_TAG 0xF2
- #define MAX_CMD_LEN 0x7
- #define MAX_CMD_PARAMS 4
- struct cmd {
- int cmd_len;
- unsigned char cmd_id;
- unsigned char no_cmd_params;
- unsigned char cmd_params[MAX_CMD_PARAMS];
- enum req_type req;
- };
- struct param_list {
- int param_offset;
- int new_param_val;
- };
- /*
- * List of top-level cmds to be used internally by the driver.
- * All these commands are build on top of ST95HF basic commands
- * such as SEND_RECEIVE_CMD, PROTOCOL_SELECT_CMD, etc.
- * These top level cmds are used internally while implementing various ops of
- * digital layer/driver probe or extending the digital framework layer for
- * features that are not yet implemented there, for example, WTX cmd handling.
- */
- enum st95hf_cmd_list {
- CMD_ECHO,
- CMD_ISO14443A_CONFIG,
- CMD_ISO14443A_DEMOGAIN,
- CMD_ISO14443B_DEMOGAIN,
- CMD_ISO14443A_PROTOCOL_SELECT,
- CMD_ISO14443B_PROTOCOL_SELECT,
- CMD_WTX_RESPONSE,
- CMD_FIELD_OFF,
- CMD_ISO15693_PROTOCOL_SELECT,
- };
- static const struct cmd cmd_array[] = {
- [CMD_ECHO] = {
- .cmd_len = 0x2,
- .cmd_id = ECHO_CMD,
- .no_cmd_params = 0,
- .req = SYNC,
- },
- [CMD_ISO14443A_CONFIG] = {
- .cmd_len = 0x7,
- .cmd_id = WRITE_REGISTER_CMD,
- .no_cmd_params = 0x4,
- .cmd_params = {0x3A, 0x00, 0x5A, 0x04},
- .req = SYNC,
- },
- [CMD_ISO14443A_DEMOGAIN] = {
- .cmd_len = 0x7,
- .cmd_id = WRITE_REGISTER_CMD,
- .no_cmd_params = 0x4,
- .cmd_params = {0x68, 0x01, 0x01, 0xDF},
- .req = SYNC,
- },
- [CMD_ISO14443B_DEMOGAIN] = {
- .cmd_len = 0x7,
- .cmd_id = WRITE_REGISTER_CMD,
- .no_cmd_params = 0x4,
- .cmd_params = {0x68, 0x01, 0x01, 0x51},
- .req = SYNC,
- },
- [CMD_ISO14443A_PROTOCOL_SELECT] = {
- .cmd_len = 0x7,
- .cmd_id = PROTOCOL_SELECT_CMD,
- .no_cmd_params = 0x4,
- .cmd_params = {ISO14443A_PROTOCOL_CODE, 0x00, 0x01, 0xA0},
- .req = SYNC,
- },
- [CMD_ISO14443B_PROTOCOL_SELECT] = {
- .cmd_len = 0x7,
- .cmd_id = PROTOCOL_SELECT_CMD,
- .no_cmd_params = 0x4,
- .cmd_params = {ISO14443B_PROTOCOL_CODE, 0x01, 0x03, 0xFF},
- .req = SYNC,
- },
- [CMD_WTX_RESPONSE] = {
- .cmd_len = 0x6,
- .cmd_id = SEND_RECEIVE_CMD,
- .no_cmd_params = 0x3,
- .cmd_params = {0xF2, 0x00, TRFLAG_NFCA_STD_FRAME_CRC},
- .req = ASYNC,
- },
- [CMD_FIELD_OFF] = {
- .cmd_len = 0x5,
- .cmd_id = PROTOCOL_SELECT_CMD,
- .no_cmd_params = 0x2,
- .cmd_params = {0x0, 0x0},
- .req = SYNC,
- },
- [CMD_ISO15693_PROTOCOL_SELECT] = {
- .cmd_len = 0x5,
- .cmd_id = PROTOCOL_SELECT_CMD,
- .no_cmd_params = 0x2,
- .cmd_params = {ISO15693_PROTOCOL_CODE, 0x0D},
- .req = SYNC,
- },
- };
- /* st95_digital_cmd_complete_arg stores client context */
- struct st95_digital_cmd_complete_arg {
- struct sk_buff *skb_resp;
- nfc_digital_cmd_complete_t complete_cb;
- void *cb_usrarg;
- bool rats;
- };
- /*
- * structure containing ST95HF driver specific data.
- * @spicontext: structure containing information required
- * for spi communication between st95hf and host.
- * @ddev: nfc digital device object.
- * @nfcdev: nfc device object.
- * @enable_gpio: gpio used to enable st95hf transceiver.
- * @complete_cb_arg: structure to store various context information
- * that is passed from nfc requesting thread to the threaded ISR.
- * @st95hf_supply: regulator "consumer" for NFC device.
- * @sendrcv_trflag: last byte of frame send by sendrecv command
- * of st95hf. This byte contains transmission flag info.
- * @exchange_lock: semaphore used for signaling the st95hf_remove
- * function that the last outstanding async nfc request is finished.
- * @rm_lock: mutex for ensuring safe access of nfc digital object
- * from threaded ISR. Usage of this mutex avoids any race between
- * deletion of the object from st95hf_remove() and its access from
- * the threaded ISR.
- * @nfcdev_free: flag to have the state of nfc device object.
- * [alive | died]
- * @current_protocol: current nfc protocol.
- * @current_rf_tech: current rf technology.
- * @fwi: frame waiting index, received in reply of RATS according to
- * digital protocol.
- */
- struct st95hf_context {
- struct st95hf_spi_context spicontext;
- struct nfc_digital_dev *ddev;
- struct nfc_dev *nfcdev;
- unsigned int enable_gpio;
- struct st95_digital_cmd_complete_arg complete_cb_arg;
- struct regulator *st95hf_supply;
- unsigned char sendrcv_trflag;
- struct semaphore exchange_lock;
- struct mutex rm_lock;
- bool nfcdev_free;
- u8 current_protocol;
- u8 current_rf_tech;
- int fwi;
- };
- /*
- * st95hf_send_recv_cmd() is for sending commands to ST95HF
- * that are described in the cmd_array[]. It can optionally
- * receive the response if the cmd request is of type
- * SYNC. For that to happen caller must pass true to recv_res.
- * For ASYNC request, recv_res is ignored and the
- * function will never try to receive the response on behalf
- * of the caller.
- */
- static int st95hf_send_recv_cmd(struct st95hf_context *st95context,
- enum st95hf_cmd_list cmd,
- int no_modif,
- struct param_list *list_array,
- bool recv_res)
- {
- unsigned char spi_cmd_buffer[MAX_CMD_LEN];
- int i, ret;
- struct device *dev = &st95context->spicontext.spidev->dev;
- if (cmd_array[cmd].cmd_len > MAX_CMD_LEN)
- return -EINVAL;
- if (cmd_array[cmd].no_cmd_params < no_modif)
- return -EINVAL;
- if (no_modif && !list_array)
- return -EINVAL;
- spi_cmd_buffer[0] = ST95HF_COMMAND_SEND;
- spi_cmd_buffer[1] = cmd_array[cmd].cmd_id;
- spi_cmd_buffer[2] = cmd_array[cmd].no_cmd_params;
- memcpy(&spi_cmd_buffer[3], cmd_array[cmd].cmd_params,
- spi_cmd_buffer[2]);
- for (i = 0; i < no_modif; i++) {
- if (list_array[i].param_offset >= cmd_array[cmd].no_cmd_params)
- return -EINVAL;
- spi_cmd_buffer[3 + list_array[i].param_offset] =
- list_array[i].new_param_val;
- }
- ret = st95hf_spi_send(&st95context->spicontext,
- spi_cmd_buffer,
- cmd_array[cmd].cmd_len,
- cmd_array[cmd].req);
- if (ret) {
- dev_err(dev, "st95hf_spi_send failed with error %d\n", ret);
- return ret;
- }
- if (cmd_array[cmd].req == SYNC && recv_res) {
- unsigned char st95hf_response_arr[2];
- ret = st95hf_spi_recv_response(&st95context->spicontext,
- st95hf_response_arr);
- if (ret < 0) {
- dev_err(dev, "spi error from st95hf_spi_recv_response(), err = 0x%x\n",
- ret);
- return ret;
- }
- if (st95hf_response_arr[0]) {
- dev_err(dev, "st95hf error from st95hf_spi_recv_response(), err = 0x%x\n",
- st95hf_response_arr[0]);
- return -EIO;
- }
- }
- return 0;
- }
- static int st95hf_echo_command(struct st95hf_context *st95context)
- {
- int result = 0;
- unsigned char echo_response;
- result = st95hf_send_recv_cmd(st95context, CMD_ECHO, 0, NULL, false);
- if (result)
- return result;
- /* If control reached here, response can be taken */
- result = st95hf_spi_recv_echo_res(&st95context->spicontext,
- &echo_response);
- if (result) {
- dev_err(&st95context->spicontext.spidev->dev,
- "err: echo response receieve error = 0x%x\n", result);
- return result;
- }
- if (echo_response == ECHORESPONSE)
- return 0;
- dev_err(&st95context->spicontext.spidev->dev, "err: echo res is 0x%x\n",
- echo_response);
- return -EIO;
- }
- static int secondary_configuration_type4a(struct st95hf_context *stcontext)
- {
- int result = 0;
- struct device *dev = &stcontext->nfcdev->dev;
- /* 14443A config setting after select protocol */
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO14443A_CONFIG,
- 0,
- NULL,
- true);
- if (result) {
- dev_err(dev, "type a config cmd, err = 0x%x\n", result);
- return result;
- }
- /* 14443A demo gain setting */
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO14443A_DEMOGAIN,
- 0,
- NULL,
- true);
- if (result)
- dev_err(dev, "type a demogain cmd, err = 0x%x\n", result);
- return result;
- }
- static int secondary_configuration_type4b(struct st95hf_context *stcontext)
- {
- int result = 0;
- struct device *dev = &stcontext->nfcdev->dev;
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO14443B_DEMOGAIN,
- 0,
- NULL,
- true);
- if (result)
- dev_err(dev, "type b demogain cmd, err = 0x%x\n", result);
- return result;
- }
- static int st95hf_select_protocol(struct st95hf_context *stcontext, int type)
- {
- int result = 0;
- struct device *dev;
- dev = &stcontext->nfcdev->dev;
- switch (type) {
- case NFC_DIGITAL_RF_TECH_106A:
- stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106A;
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO14443A_PROTOCOL_SELECT,
- 0,
- NULL,
- true);
- if (result) {
- dev_err(dev, "protocol sel, err = 0x%x\n",
- result);
- return result;
- }
- /* secondary config. for 14443Type 4A after protocol select */
- result = secondary_configuration_type4a(stcontext);
- if (result) {
- dev_err(dev, "type a secondary config, err = 0x%x\n",
- result);
- return result;
- }
- break;
- case NFC_DIGITAL_RF_TECH_106B:
- stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_106B;
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO14443B_PROTOCOL_SELECT,
- 0,
- NULL,
- true);
- if (result) {
- dev_err(dev, "protocol sel send, err = 0x%x\n",
- result);
- return result;
- }
- /*
- * delay of 5-6 ms is required after select protocol
- * command in case of ISO14443 Type B
- */
- usleep_range(50000, 60000);
- /* secondary config. for 14443Type 4B after protocol select */
- result = secondary_configuration_type4b(stcontext);
- if (result) {
- dev_err(dev, "type b secondary config, err = 0x%x\n",
- result);
- return result;
- }
- break;
- case NFC_DIGITAL_RF_TECH_ISO15693:
- stcontext->current_rf_tech = NFC_DIGITAL_RF_TECH_ISO15693;
- result = st95hf_send_recv_cmd(stcontext,
- CMD_ISO15693_PROTOCOL_SELECT,
- 0,
- NULL,
- true);
- if (result) {
- dev_err(dev, "protocol sel send, err = 0x%x\n",
- result);
- return result;
- }
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static void st95hf_send_st95enable_negativepulse(struct st95hf_context *st95con)
- {
- /* First make irq_in pin high */
- gpio_set_value(st95con->enable_gpio, HIGH);
- /* wait for 1 milisecond */
- usleep_range(1000, 2000);
- /* Make irq_in pin low */
- gpio_set_value(st95con->enable_gpio, LOW);
- /* wait for minimum interrupt pulse to make st95 active */
- usleep_range(1000, 2000);
- /* At end make it high */
- gpio_set_value(st95con->enable_gpio, HIGH);
- }
- /*
- * Send a reset sequence over SPI bus (Reset command + wait 3ms +
- * negative pulse on st95hf enable gpio
- */
- static int st95hf_send_spi_reset_sequence(struct st95hf_context *st95context)
- {
- int result = 0;
- unsigned char reset_cmd = ST95HF_COMMAND_RESET;
- result = st95hf_spi_send(&st95context->spicontext,
- &reset_cmd,
- ST95HF_RESET_CMD_LEN,
- ASYNC);
- if (result) {
- dev_err(&st95context->spicontext.spidev->dev,
- "spi reset sequence cmd error = %d", result);
- return result;
- }
- /* wait for 3 milisecond to complete the controller reset process */
- usleep_range(3000, 4000);
- /* send negative pulse to make st95hf active */
- st95hf_send_st95enable_negativepulse(st95context);
- /* wait for 10 milisecond : HFO setup time */
- usleep_range(10000, 20000);
- return result;
- }
- static int st95hf_por_sequence(struct st95hf_context *st95context)
- {
- int nth_attempt = 1;
- int result;
- st95hf_send_st95enable_negativepulse(st95context);
- usleep_range(5000, 6000);
- do {
- /* send an ECHO command and checks ST95HF response */
- result = st95hf_echo_command(st95context);
- dev_dbg(&st95context->spicontext.spidev->dev,
- "response from echo function = 0x%x, attempt = %d\n",
- result, nth_attempt);
- if (!result)
- return 0;
- /* send an pulse on IRQ in case of the chip is on sleep state */
- if (nth_attempt == 2)
- st95hf_send_st95enable_negativepulse(st95context);
- else
- st95hf_send_spi_reset_sequence(st95context);
- /* delay of 50 milisecond */
- usleep_range(50000, 51000);
- } while (nth_attempt++ < 3);
- return -ETIMEDOUT;
- }
- static int iso14443_config_fdt(struct st95hf_context *st95context, int wtxm)
- {
- int result = 0;
- struct device *dev = &st95context->spicontext.spidev->dev;
- struct nfc_digital_dev *nfcddev = st95context->ddev;
- unsigned char pp_typeb;
- struct param_list new_params[2];
- pp_typeb = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[2];
- if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 &&
- st95context->fwi < 4)
- st95context->fwi = 4;
- new_params[0].param_offset = 2;
- if (nfcddev->curr_protocol == NFC_PROTO_ISO14443)
- new_params[0].new_param_val = st95context->fwi;
- else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B)
- new_params[0].new_param_val = pp_typeb;
- new_params[1].param_offset = 3;
- new_params[1].new_param_val = wtxm;
- switch (nfcddev->curr_protocol) {
- case NFC_PROTO_ISO14443:
- result = st95hf_send_recv_cmd(st95context,
- CMD_ISO14443A_PROTOCOL_SELECT,
- 2,
- new_params,
- true);
- if (result) {
- dev_err(dev, "WTX type a sel proto, err = 0x%x\n",
- result);
- return result;
- }
- /* secondary config. for 14443Type 4A after protocol select */
- result = secondary_configuration_type4a(st95context);
- if (result) {
- dev_err(dev, "WTX type a second. config, err = 0x%x\n",
- result);
- return result;
- }
- break;
- case NFC_PROTO_ISO14443_B:
- result = st95hf_send_recv_cmd(st95context,
- CMD_ISO14443B_PROTOCOL_SELECT,
- 2,
- new_params,
- true);
- if (result) {
- dev_err(dev, "WTX type b sel proto, err = 0x%x\n",
- result);
- return result;
- }
- /* secondary config. for 14443Type 4B after protocol select */
- result = secondary_configuration_type4b(st95context);
- if (result) {
- dev_err(dev, "WTX type b second. config, err = 0x%x\n",
- result);
- return result;
- }
- break;
- default:
- return -EINVAL;
- }
- return 0;
- }
- static int st95hf_handle_wtx(struct st95hf_context *stcontext,
- bool new_wtx,
- int wtx_val)
- {
- int result = 0;
- unsigned char val_mm = 0;
- struct param_list new_params[1];
- struct nfc_digital_dev *nfcddev = stcontext->ddev;
- struct device *dev = &stcontext->nfcdev->dev;
- if (new_wtx) {
- result = iso14443_config_fdt(stcontext, wtx_val & 0x3f);
- if (result) {
- dev_err(dev, "Config. setting error on WTX req, err = 0x%x\n",
- result);
- return result;
- }
- /* Send response of wtx with ASYNC as no response expected */
- new_params[0].param_offset = 1;
- new_params[0].new_param_val = wtx_val;
- result = st95hf_send_recv_cmd(stcontext,
- CMD_WTX_RESPONSE,
- 1,
- new_params,
- false);
- if (result)
- dev_err(dev, "WTX response send, err = 0x%x\n", result);
- return result;
- }
- /* if no new wtx, cofigure with default values */
- if (nfcddev->curr_protocol == NFC_PROTO_ISO14443)
- val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3];
- else if (nfcddev->curr_protocol == NFC_PROTO_ISO14443_B)
- val_mm = cmd_array[CMD_ISO14443B_PROTOCOL_SELECT].cmd_params[3];
- result = iso14443_config_fdt(stcontext, val_mm);
- if (result)
- dev_err(dev, "Default config. setting error after WTX processing, err = 0x%x\n",
- result);
- return result;
- }
- static int st95hf_error_handling(struct st95hf_context *stcontext,
- struct sk_buff *skb_resp,
- int res_len)
- {
- int result = 0;
- unsigned char error_byte;
- struct device *dev = &stcontext->nfcdev->dev;
- /* First check ST95HF specific error */
- if (skb_resp->data[0] & ST95HF_ERR_MASK) {
- if (skb_resp->data[0] == ST95HF_TIMEOUT_ERROR)
- result = -ETIMEDOUT;
- else
- result = -EIO;
- return result;
- }
- /* Check for CRC err only if CRC is present in the tag response */
- switch (stcontext->current_rf_tech) {
- case NFC_DIGITAL_RF_TECH_106A:
- if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC) {
- error_byte = skb_resp->data[res_len - 3];
- if (error_byte & ST95HF_NFCA_CRC_ERR_MASK) {
- /* CRC error occurred */
- dev_err(dev, "CRC error, byte received = 0x%x\n",
- error_byte);
- result = -EIO;
- }
- }
- break;
- case NFC_DIGITAL_RF_TECH_106B:
- case NFC_DIGITAL_RF_TECH_ISO15693:
- error_byte = skb_resp->data[res_len - 1];
- if (error_byte & ST95HF_NFCB_CRC_ERR_MASK) {
- /* CRC error occurred */
- dev_err(dev, "CRC error, byte received = 0x%x\n",
- error_byte);
- result = -EIO;
- }
- break;
- }
- return result;
- }
- static int st95hf_response_handler(struct st95hf_context *stcontext,
- struct sk_buff *skb_resp,
- int res_len)
- {
- int result = 0;
- int skb_len;
- unsigned char val_mm;
- struct nfc_digital_dev *nfcddev = stcontext->ddev;
- struct device *dev = &stcontext->nfcdev->dev;
- struct st95_digital_cmd_complete_arg *cb_arg;
- cb_arg = &stcontext->complete_cb_arg;
- /* Process the response */
- skb_put(skb_resp, res_len);
- /* Remove st95 header */
- skb_pull(skb_resp, 2);
- skb_len = skb_resp->len;
- /* check if it is case of RATS request reply & FWI is present */
- if (nfcddev->curr_protocol == NFC_PROTO_ISO14443 && cb_arg->rats &&
- (skb_resp->data[1] & RATS_TB1_PRESENT_MASK)) {
- if (skb_resp->data[1] & RATS_TA1_PRESENT_MASK)
- stcontext->fwi =
- (skb_resp->data[3] & TB1_FWI_MASK) >> 4;
- else
- stcontext->fwi =
- (skb_resp->data[2] & TB1_FWI_MASK) >> 4;
- val_mm = cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[3];
- result = iso14443_config_fdt(stcontext, val_mm);
- if (result) {
- dev_err(dev, "error in config_fdt to handle fwi of ATS, error=%d\n",
- result);
- return result;
- }
- }
- cb_arg->rats = false;
- /* Remove CRC bytes only if received frames data has an eod (CRC) */
- switch (stcontext->current_rf_tech) {
- case NFC_DIGITAL_RF_TECH_106A:
- if (stcontext->sendrcv_trflag == TRFLAG_NFCA_STD_FRAME_CRC)
- skb_trim(skb_resp, (skb_len - 5));
- else
- skb_trim(skb_resp, (skb_len - 3));
- break;
- case NFC_DIGITAL_RF_TECH_106B:
- case NFC_DIGITAL_RF_TECH_ISO15693:
- skb_trim(skb_resp, (skb_len - 3));
- break;
- }
- return result;
- }
- static irqreturn_t st95hf_irq_handler(int irq, void *st95hfcontext)
- {
- struct st95hf_context *stcontext =
- (struct st95hf_context *)st95hfcontext;
- if (stcontext->spicontext.req_issync) {
- complete(&stcontext->spicontext.done);
- stcontext->spicontext.req_issync = false;
- return IRQ_HANDLED;
- }
- return IRQ_WAKE_THREAD;
- }
- static irqreturn_t st95hf_irq_thread_handler(int irq, void *st95hfcontext)
- {
- int result = 0;
- int res_len;
- static bool wtx;
- struct device *dev;
- struct device *spidevice;
- struct nfc_digital_dev *nfcddev;
- struct sk_buff *skb_resp;
- struct st95hf_context *stcontext =
- (struct st95hf_context *)st95hfcontext;
- struct st95_digital_cmd_complete_arg *cb_arg;
- spidevice = &stcontext->spicontext.spidev->dev;
- /*
- * check semaphore, if not down() already, then we don't
- * know in which context the ISR is called and surely it
- * will be a bug. Note that down() of the semaphore is done
- * in the corresponding st95hf_in_send_cmd() and then
- * only this ISR should be called. ISR will up() the
- * semaphore before leaving. Hence when the ISR is called
- * the correct behaviour is down_trylock() should always
- * return 1 (indicating semaphore cant be taken and hence no
- * change in semaphore count).
- * If not, then we up() the semaphore and crash on
- * a BUG() !
- */
- if (!down_trylock(&stcontext->exchange_lock)) {
- up(&stcontext->exchange_lock);
- WARN(1, "unknown context in ST95HF ISR");
- return IRQ_NONE;
- }
- cb_arg = &stcontext->complete_cb_arg;
- skb_resp = cb_arg->skb_resp;
- mutex_lock(&stcontext->rm_lock);
- res_len = st95hf_spi_recv_response(&stcontext->spicontext,
- skb_resp->data);
- if (res_len < 0) {
- dev_err(spidevice, "TISR spi response err = 0x%x\n", res_len);
- result = res_len;
- goto end;
- }
- /* if stcontext->nfcdev_free is true, it means remove already ran */
- if (stcontext->nfcdev_free) {
- result = -ENODEV;
- goto end;
- }
- dev = &stcontext->nfcdev->dev;
- nfcddev = stcontext->ddev;
- if (skb_resp->data[2] == WTX_REQ_FROM_TAG) {
- /* Request for new FWT from tag */
- result = st95hf_handle_wtx(stcontext, true, skb_resp->data[3]);
- if (result)
- goto end;
- wtx = true;
- mutex_unlock(&stcontext->rm_lock);
- return IRQ_HANDLED;
- }
- result = st95hf_error_handling(stcontext, skb_resp, res_len);
- if (result)
- goto end;
- result = st95hf_response_handler(stcontext, skb_resp, res_len);
- if (result)
- goto end;
- /*
- * If select protocol is done on wtx req. do select protocol
- * again with default values
- */
- if (wtx) {
- wtx = false;
- result = st95hf_handle_wtx(stcontext, false, 0);
- if (result)
- goto end;
- }
- /* call digital layer callback */
- cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);
- /* up the semaphore before returning */
- up(&stcontext->exchange_lock);
- mutex_unlock(&stcontext->rm_lock);
- return IRQ_HANDLED;
- end:
- kfree_skb(skb_resp);
- wtx = false;
- cb_arg->rats = false;
- skb_resp = ERR_PTR(result);
- /* call of callback with error */
- cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);
- /* up the semaphore before returning */
- up(&stcontext->exchange_lock);
- mutex_unlock(&stcontext->rm_lock);
- return IRQ_HANDLED;
- }
- /* NFC ops functions definition */
- static int st95hf_in_configure_hw(struct nfc_digital_dev *ddev,
- int type,
- int param)
- {
- struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
- if (type == NFC_DIGITAL_CONFIG_RF_TECH)
- return st95hf_select_protocol(stcontext, param);
- if (type == NFC_DIGITAL_CONFIG_FRAMING) {
- switch (param) {
- case NFC_DIGITAL_FRAMING_NFCA_SHORT:
- stcontext->sendrcv_trflag = TRFLAG_NFCA_SHORT_FRAME;
- break;
- case NFC_DIGITAL_FRAMING_NFCA_STANDARD:
- stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME;
- break;
- case NFC_DIGITAL_FRAMING_NFCA_T4T:
- case NFC_DIGITAL_FRAMING_NFCA_NFC_DEP:
- case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A:
- stcontext->sendrcv_trflag = TRFLAG_NFCA_STD_FRAME_CRC;
- break;
- case NFC_DIGITAL_FRAMING_NFCB:
- case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY:
- case NFC_DIGITAL_FRAMING_ISO15693_T5T:
- break;
- }
- }
- return 0;
- }
- static int rf_off(struct st95hf_context *stcontext)
- {
- int rc;
- struct device *dev;
- dev = &stcontext->nfcdev->dev;
- rc = st95hf_send_recv_cmd(stcontext, CMD_FIELD_OFF, 0, NULL, true);
- if (rc)
- dev_err(dev, "protocol sel send field off, err = 0x%x\n", rc);
- return rc;
- }
- static int st95hf_in_send_cmd(struct nfc_digital_dev *ddev,
- struct sk_buff *skb,
- u16 timeout,
- nfc_digital_cmd_complete_t cb,
- void *arg)
- {
- struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
- int rc;
- struct sk_buff *skb_resp;
- int len_data_to_tag = 0;
- skb_resp = nfc_alloc_recv_skb(MAX_RESPONSE_BUFFER_SIZE, GFP_KERNEL);
- if (!skb_resp) {
- rc = -ENOMEM;
- goto error;
- }
- switch (stcontext->current_rf_tech) {
- case NFC_DIGITAL_RF_TECH_106A:
- len_data_to_tag = skb->len + 1;
- *skb_put(skb, 1) = stcontext->sendrcv_trflag;
- break;
- case NFC_DIGITAL_RF_TECH_106B:
- case NFC_DIGITAL_RF_TECH_ISO15693:
- len_data_to_tag = skb->len;
- break;
- default:
- rc = -EINVAL;
- goto free_skb_resp;
- }
- skb_push(skb, 3);
- skb->data[0] = ST95HF_COMMAND_SEND;
- skb->data[1] = SEND_RECEIVE_CMD;
- skb->data[2] = len_data_to_tag;
- stcontext->complete_cb_arg.skb_resp = skb_resp;
- stcontext->complete_cb_arg.cb_usrarg = arg;
- stcontext->complete_cb_arg.complete_cb = cb;
- if ((skb->data[3] == ISO14443A_RATS_REQ) &&
- ddev->curr_protocol == NFC_PROTO_ISO14443)
- stcontext->complete_cb_arg.rats = true;
- /*
- * down the semaphore to indicate to remove func that an
- * ISR is pending, note that it will not block here in any case.
- * If found blocked, it is a BUG!
- */
- rc = down_killable(&stcontext->exchange_lock);
- if (rc) {
- WARN(1, "Semaphore is not found up in st95hf_in_send_cmd\n");
- return rc;
- }
- rc = st95hf_spi_send(&stcontext->spicontext, skb->data,
- skb->len,
- ASYNC);
- if (rc) {
- dev_err(&stcontext->nfcdev->dev,
- "Error %d trying to perform data_exchange", rc);
- /* up the semaphore since ISR will never come in this case */
- up(&stcontext->exchange_lock);
- goto free_skb_resp;
- }
- kfree_skb(skb);
- return rc;
- free_skb_resp:
- kfree_skb(skb_resp);
- error:
- return rc;
- }
- /* p2p will be supported in a later release ! */
- static int st95hf_tg_configure_hw(struct nfc_digital_dev *ddev,
- int type,
- int param)
- {
- return 0;
- }
- static int st95hf_tg_send_cmd(struct nfc_digital_dev *ddev,
- struct sk_buff *skb,
- u16 timeout,
- nfc_digital_cmd_complete_t cb,
- void *arg)
- {
- return 0;
- }
- static int st95hf_tg_listen(struct nfc_digital_dev *ddev,
- u16 timeout,
- nfc_digital_cmd_complete_t cb,
- void *arg)
- {
- return 0;
- }
- static int st95hf_tg_get_rf_tech(struct nfc_digital_dev *ddev, u8 *rf_tech)
- {
- return 0;
- }
- static int st95hf_switch_rf(struct nfc_digital_dev *ddev, bool on)
- {
- u8 rf_tech;
- struct st95hf_context *stcontext = nfc_digital_get_drvdata(ddev);
- rf_tech = ddev->curr_rf_tech;
- if (on)
- /* switch on RF field */
- return st95hf_select_protocol(stcontext, rf_tech);
- /* switch OFF RF field */
- return rf_off(stcontext);
- }
- /* TODO st95hf_abort_cmd */
- static void st95hf_abort_cmd(struct nfc_digital_dev *ddev)
- {
- }
- static struct nfc_digital_ops st95hf_nfc_digital_ops = {
- .in_configure_hw = st95hf_in_configure_hw,
- .in_send_cmd = st95hf_in_send_cmd,
- .tg_listen = st95hf_tg_listen,
- .tg_configure_hw = st95hf_tg_configure_hw,
- .tg_send_cmd = st95hf_tg_send_cmd,
- .tg_get_rf_tech = st95hf_tg_get_rf_tech,
- .switch_rf = st95hf_switch_rf,
- .abort_cmd = st95hf_abort_cmd,
- };
- static const struct spi_device_id st95hf_id[] = {
- { "st95hf", 0 },
- {}
- };
- MODULE_DEVICE_TABLE(spi, st95hf_id);
- static int st95hf_probe(struct spi_device *nfc_spi_dev)
- {
- int ret;
- struct st95hf_context *st95context;
- struct st95hf_spi_context *spicontext;
- nfc_info(&nfc_spi_dev->dev, "ST95HF driver probe called.\n");
- st95context = devm_kzalloc(&nfc_spi_dev->dev,
- sizeof(struct st95hf_context),
- GFP_KERNEL);
- if (!st95context)
- return -ENOMEM;
- spicontext = &st95context->spicontext;
- spicontext->spidev = nfc_spi_dev;
- st95context->fwi =
- cmd_array[CMD_ISO14443A_PROTOCOL_SELECT].cmd_params[2];
- if (device_property_present(&nfc_spi_dev->dev, "st95hfvin")) {
- st95context->st95hf_supply =
- devm_regulator_get(&nfc_spi_dev->dev,
- "st95hfvin");
- if (IS_ERR(st95context->st95hf_supply)) {
- dev_err(&nfc_spi_dev->dev, "failed to acquire regulator\n");
- return PTR_ERR(st95context->st95hf_supply);
- }
- ret = regulator_enable(st95context->st95hf_supply);
- if (ret) {
- dev_err(&nfc_spi_dev->dev, "failed to enable regulator\n");
- return ret;
- }
- }
- init_completion(&spicontext->done);
- mutex_init(&spicontext->spi_lock);
- /*
- * Store spicontext in spi device object for using it in
- * remove function
- */
- dev_set_drvdata(&nfc_spi_dev->dev, spicontext);
- st95context->enable_gpio =
- of_get_named_gpio(nfc_spi_dev->dev.of_node,
- "enable-gpio",
- 0);
- if (!gpio_is_valid(st95context->enable_gpio)) {
- dev_err(&nfc_spi_dev->dev, "No valid enable gpio\n");
- ret = st95context->enable_gpio;
- goto err_disable_regulator;
- }
- ret = devm_gpio_request_one(&nfc_spi_dev->dev, st95context->enable_gpio,
- GPIOF_DIR_OUT | GPIOF_INIT_HIGH,
- "enable_gpio");
- if (ret)
- goto err_disable_regulator;
- if (nfc_spi_dev->irq > 0) {
- if (devm_request_threaded_irq(&nfc_spi_dev->dev,
- nfc_spi_dev->irq,
- st95hf_irq_handler,
- st95hf_irq_thread_handler,
- IRQF_TRIGGER_FALLING,
- "st95hf",
- (void *)st95context) < 0) {
- dev_err(&nfc_spi_dev->dev, "err: irq request for st95hf is failed\n");
- ret = -EINVAL;
- goto err_disable_regulator;
- }
- } else {
- dev_err(&nfc_spi_dev->dev, "not a valid IRQ associated with ST95HF\n");
- ret = -EINVAL;
- goto err_disable_regulator;
- }
- /*
- * First reset SPI to handle warm reset of the system.
- * It will put the ST95HF device in Power ON state
- * which make the state of device identical to state
- * at the time of cold reset of the system.
- */
- ret = st95hf_send_spi_reset_sequence(st95context);
- if (ret) {
- dev_err(&nfc_spi_dev->dev, "err: spi_reset_sequence failed\n");
- goto err_disable_regulator;
- }
- /* call PowerOnReset sequence of ST95hf to activate it */
- ret = st95hf_por_sequence(st95context);
- if (ret) {
- dev_err(&nfc_spi_dev->dev, "err: por seq failed for st95hf\n");
- goto err_disable_regulator;
- }
- /* create NFC dev object and register with NFC Subsystem */
- st95context->ddev = nfc_digital_allocate_device(&st95hf_nfc_digital_ops,
- ST95HF_SUPPORTED_PROT,
- ST95HF_CAPABILITIES,
- ST95HF_HEADROOM_LEN,
- ST95HF_TAILROOM_LEN);
- if (!st95context->ddev) {
- ret = -ENOMEM;
- goto err_disable_regulator;
- }
- st95context->nfcdev = st95context->ddev->nfc_dev;
- nfc_digital_set_parent_dev(st95context->ddev, &nfc_spi_dev->dev);
- ret = nfc_digital_register_device(st95context->ddev);
- if (ret) {
- dev_err(&st95context->nfcdev->dev, "st95hf registration failed\n");
- goto err_free_digital_device;
- }
- /* store st95context in nfc device object */
- nfc_digital_set_drvdata(st95context->ddev, st95context);
- sema_init(&st95context->exchange_lock, 1);
- mutex_init(&st95context->rm_lock);
- return ret;
- err_free_digital_device:
- nfc_digital_free_device(st95context->ddev);
- err_disable_regulator:
- if (st95context->st95hf_supply)
- regulator_disable(st95context->st95hf_supply);
- return ret;
- }
- static int st95hf_remove(struct spi_device *nfc_spi_dev)
- {
- int result = 0;
- unsigned char reset_cmd = ST95HF_COMMAND_RESET;
- struct st95hf_spi_context *spictx = dev_get_drvdata(&nfc_spi_dev->dev);
- struct st95hf_context *stcontext = container_of(spictx,
- struct st95hf_context,
- spicontext);
- mutex_lock(&stcontext->rm_lock);
- nfc_digital_unregister_device(stcontext->ddev);
- nfc_digital_free_device(stcontext->ddev);
- stcontext->nfcdev_free = true;
- mutex_unlock(&stcontext->rm_lock);
- /* if last in_send_cmd's ISR is pending, wait for it to finish */
- result = down_killable(&stcontext->exchange_lock);
- if (result == -EINTR)
- dev_err(&spictx->spidev->dev, "sleep for semaphore interrupted by signal\n");
- /* next reset the ST95HF controller */
- result = st95hf_spi_send(&stcontext->spicontext,
- &reset_cmd,
- ST95HF_RESET_CMD_LEN,
- ASYNC);
- if (result) {
- dev_err(&spictx->spidev->dev,
- "ST95HF reset failed in remove() err = %d\n", result);
- return result;
- }
- /* wait for 3 ms to complete the controller reset process */
- usleep_range(3000, 4000);
- /* disable regulator */
- if (stcontext->st95hf_supply)
- regulator_disable(stcontext->st95hf_supply);
- return result;
- }
- /* Register as SPI protocol driver */
- static struct spi_driver st95hf_driver = {
- .driver = {
- .name = "st95hf",
- .owner = THIS_MODULE,
- },
- .id_table = st95hf_id,
- .probe = st95hf_probe,
- .remove = st95hf_remove,
- };
- module_spi_driver(st95hf_driver);
- MODULE_AUTHOR("Shikha Singh <shikha.singh@st.com>");
- MODULE_DESCRIPTION("ST NFC Transceiver ST95HF driver");
- MODULE_LICENSE("GPL v2");
|