mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	NFC: Add STMicroelectronics ST95HF driver
This driver supports STMicroelectronics NFC Transceiver "ST95HF", in in initiator role to read/write ISO14443 Type 4A, ISO14443 Type 4B and ISO15693 Type5 tags. The ST95HF datasheet is available here: http://www.st.com/web/en/resource/technical/document/datasheet/DM00102056.pdf Signed-off-by: Shikha Singh <shikha.singh@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
		
							parent
							
								
									ce2e56cdfb
								
							
						
					
					
						commit
						cab47333f0
					
				
					 7 changed files with 1522 additions and 0 deletions
				
			
		| 
						 | 
					@ -76,4 +76,5 @@ source "drivers/nfc/st21nfca/Kconfig"
 | 
				
			||||||
source "drivers/nfc/st-nci/Kconfig"
 | 
					source "drivers/nfc/st-nci/Kconfig"
 | 
				
			||||||
source "drivers/nfc/nxp-nci/Kconfig"
 | 
					source "drivers/nfc/nxp-nci/Kconfig"
 | 
				
			||||||
source "drivers/nfc/s3fwrn5/Kconfig"
 | 
					source "drivers/nfc/s3fwrn5/Kconfig"
 | 
				
			||||||
 | 
					source "drivers/nfc/st95hf/Kconfig"
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,3 +16,4 @@ obj-$(CONFIG_NFC_ST21NFCA)  	+= st21nfca/
 | 
				
			||||||
obj-$(CONFIG_NFC_ST_NCI)	+= st-nci/
 | 
					obj-$(CONFIG_NFC_ST_NCI)	+= st-nci/
 | 
				
			||||||
obj-$(CONFIG_NFC_NXP_NCI)	+= nxp-nci/
 | 
					obj-$(CONFIG_NFC_NXP_NCI)	+= nxp-nci/
 | 
				
			||||||
obj-$(CONFIG_NFC_S3FWRN5)	+= s3fwrn5/
 | 
					obj-$(CONFIG_NFC_S3FWRN5)	+= s3fwrn5/
 | 
				
			||||||
 | 
					obj-$(CONFIG_NFC_ST95HF)	+= st95hf/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								drivers/nfc/st95hf/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								drivers/nfc/st95hf/Kconfig
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					config NFC_ST95HF
 | 
				
			||||||
 | 
						tristate "ST95HF NFC Transceiver driver"
 | 
				
			||||||
 | 
						depends on SPI && NFC_DIGITAL
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						This enables the ST NFC driver for ST95HF NFC transceiver.
 | 
				
			||||||
 | 
						This makes use of SPI framework to communicate with transceiver
 | 
				
			||||||
 | 
						and registered with NFC digital core to support Linux NFC framework.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Say Y here to compile support for ST NFC transceiver ST95HF
 | 
				
			||||||
 | 
						linux driver into the kernel or say M to compile it as module.
 | 
				
			||||||
							
								
								
									
										6
									
								
								drivers/nfc/st95hf/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								drivers/nfc/st95hf/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Makefile for STMicroelectronics NFC transceiver ST95HF
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_NFC_ST95HF)	+= st95hf.o
 | 
				
			||||||
 | 
					st95hf-objs			:= spi.o core.o
 | 
				
			||||||
							
								
								
									
										1273
									
								
								drivers/nfc/st95hf/core.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1273
									
								
								drivers/nfc/st95hf/core.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										167
									
								
								drivers/nfc/st95hf/spi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								drivers/nfc/st95hf/spi.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,167 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * drivers/nfc/st95hf/spi.c function definitions for SPI communication
 | 
				
			||||||
 | 
					 * ----------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * 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 "spi.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Function to send user provided buffer to ST95HF through SPI */
 | 
				
			||||||
 | 
					int st95hf_spi_send(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
							    unsigned char *buffertx,
 | 
				
			||||||
 | 
							    int datalen,
 | 
				
			||||||
 | 
							    enum req_type reqtype)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct spi_message m;
 | 
				
			||||||
 | 
						int result = 0;
 | 
				
			||||||
 | 
						struct spi_device *spidev = spicontext->spidev;
 | 
				
			||||||
 | 
						struct spi_transfer tx_transfer = {
 | 
				
			||||||
 | 
							.tx_buf = buffertx,
 | 
				
			||||||
 | 
							.len = datalen,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (reqtype == SYNC) {
 | 
				
			||||||
 | 
							spicontext->req_issync = true;
 | 
				
			||||||
 | 
							reinit_completion(&spicontext->done);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							spicontext->req_issync = false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spi_message_init(&m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&tx_transfer, &m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = spi_sync(spidev, &m);
 | 
				
			||||||
 | 
						if (result) {
 | 
				
			||||||
 | 
							dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
 | 
				
			||||||
 | 
								result);
 | 
				
			||||||
 | 
							mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* return for asynchronous or no-wait case */
 | 
				
			||||||
 | 
						if (reqtype == ASYNC) {
 | 
				
			||||||
 | 
							mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = wait_for_completion_timeout(&spicontext->done,
 | 
				
			||||||
 | 
										     msecs_to_jiffies(1000));
 | 
				
			||||||
 | 
						/* check for timeout or success */
 | 
				
			||||||
 | 
						if (!result) {
 | 
				
			||||||
 | 
							dev_err(&spidev->dev, "error: response not ready timeout\n");
 | 
				
			||||||
 | 
							result = -ETIMEDOUT;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							result = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(st95hf_spi_send);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Function to Receive command Response */
 | 
				
			||||||
 | 
					int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
								     unsigned char *receivebuff)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int len = 0;
 | 
				
			||||||
 | 
						struct spi_transfer tx_takedata;
 | 
				
			||||||
 | 
						struct spi_message m;
 | 
				
			||||||
 | 
						struct spi_device *spidev = spicontext->spidev;
 | 
				
			||||||
 | 
						unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
 | 
				
			||||||
 | 
						struct spi_transfer t[2] = {
 | 
				
			||||||
 | 
							{.tx_buf = &readdata_cmd, .len = 1,},
 | 
				
			||||||
 | 
							{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* First spi transfer to know the length of valid data */
 | 
				
			||||||
 | 
						spi_message_init(&m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&t[0], &m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&t[1], &m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = spi_sync(spidev, &m);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
 | 
				
			||||||
 | 
								ret);
 | 
				
			||||||
 | 
							mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* As 2 bytes are already read */
 | 
				
			||||||
 | 
						len = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Support of long frame */
 | 
				
			||||||
 | 
						if (receivebuff[0] & 0x60)
 | 
				
			||||||
 | 
							len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							len += receivebuff[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Now make a transfer to read only relevant bytes */
 | 
				
			||||||
 | 
						tx_takedata.rx_buf = &receivebuff[2];
 | 
				
			||||||
 | 
						tx_takedata.len = len - 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spi_message_init(&m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&tx_takedata, &m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = spi_sync(spidev, &m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
 | 
				
			||||||
 | 
								ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return len;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
								     unsigned char *receivebuff)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
 | 
				
			||||||
 | 
						struct spi_transfer t[2] = {
 | 
				
			||||||
 | 
							{.tx_buf = &readdata_cmd, .len = 1,},
 | 
				
			||||||
 | 
							{.rx_buf = receivebuff, .len = 1,},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						struct spi_message m;
 | 
				
			||||||
 | 
						struct spi_device *spidev = spicontext->spidev;
 | 
				
			||||||
 | 
						int ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_lock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spi_message_init(&m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&t[0], &m);
 | 
				
			||||||
 | 
						spi_message_add_tail(&t[1], &m);
 | 
				
			||||||
 | 
						ret = spi_sync(spidev, &m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mutex_unlock(&spicontext->spi_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (ret)
 | 
				
			||||||
 | 
							dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
 | 
				
			||||||
 | 
								ret);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);
 | 
				
			||||||
							
								
								
									
										64
									
								
								drivers/nfc/st95hf/spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								drivers/nfc/st95hf/spi.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * drivers/nfc/st95hf/spi.h functions declarations for SPI communication
 | 
				
			||||||
 | 
					 * ---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 STMicroelectronics – 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/>.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __LINUX_ST95HF_SPI_H
 | 
				
			||||||
 | 
					#define __LINUX_ST95HF_SPI_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/spi/spi.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Basic ST95HF SPI CMDs */
 | 
				
			||||||
 | 
					#define ST95HF_COMMAND_SEND	0x0
 | 
				
			||||||
 | 
					#define ST95HF_COMMAND_RESET	0x1
 | 
				
			||||||
 | 
					#define ST95HF_COMMAND_RECEIVE	0x2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ST95HF_RESET_CMD_LEN	0x1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * structure to contain st95hf spi communication specific information.
 | 
				
			||||||
 | 
					 * @req_issync: true for synchronous calls.
 | 
				
			||||||
 | 
					 * @spidev: st95hf spi device object.
 | 
				
			||||||
 | 
					 * @done: completion structure to wait for st95hf response
 | 
				
			||||||
 | 
					 *	for synchronous calls.
 | 
				
			||||||
 | 
					 * @spi_lock: mutex to allow only one spi transfer at a time.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct st95hf_spi_context {
 | 
				
			||||||
 | 
						bool req_issync;
 | 
				
			||||||
 | 
						struct spi_device *spidev;
 | 
				
			||||||
 | 
						struct completion done;
 | 
				
			||||||
 | 
						struct mutex spi_lock;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* flag to differentiate synchronous & asynchronous spi request */
 | 
				
			||||||
 | 
					enum req_type {
 | 
				
			||||||
 | 
						SYNC,
 | 
				
			||||||
 | 
						ASYNC,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int st95hf_spi_send(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
							    unsigned char *buffertx,
 | 
				
			||||||
 | 
							    int datalen,
 | 
				
			||||||
 | 
							    enum req_type reqtype);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
								     unsigned char *receivebuff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
 | 
				
			||||||
 | 
								     unsigned char *receivebuff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in a new issue