diff options
author | John W. Linville <linville@tuxdriver.com> | 2014-03-17 13:16:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-03-17 13:16:50 -0400 |
commit | 20d83f2464c0d1e27b24d654aa5495dcc44759c0 (patch) | |
tree | a6c36d9e48920f6d81b7dac9ad6b1f99dfdaf592 | |
parent | 5f667642f4b290b04d88d5ca926fba81fed6180d (diff) | |
parent | 29e27dd86b5c4f8e6feb62d7b6a8491539ff1ef1 (diff) | |
download | talos-obmc-linux-20d83f2464c0d1e27b24d654aa5495dcc44759c0.tar.gz talos-obmc-linux-20d83f2464c0d1e27b24d654aa5495dcc44759c0.zip |
Merge tag 'nfc-next-3.15-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next
Samuel Ortiz <sameo@linux.intel.com> says:
"NFC: 3.15: First pull request
This is the NFC pull request for 3.15. With this one we have:
- Support for ISO 15693 a.k.a. NFC vicinity a.k.a. Type 5 tags. ISO
15693 are long range (1 - 2 meters) vicinity tags/cards. The kernel
now supports those through the NFC netlink and digital APIs.
- Support for TI's trf7970a chipset. This chipset relies on the NFC
digital layer and the driver currently supports type 2, 4A and 5 tags.
- Support for NXP's pn544 secure firmare download. The pn544 C3 chipsets
relies on a different firmware download protocal than the C2 one. We
now support both and use the right one depending on the version we
detect at runtime.
- Support for 4A tags from the NFC digital layer.
- A bunch of cleanups and minor fixes from Axel Lin and Thierry Escande."
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | Documentation/devicetree/bindings/net/nfc/trf7970a.txt | 34 | ||||
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/nfc/Kconfig | 12 | ||||
-rw-r--r-- | drivers/nfc/Makefile | 1 | ||||
-rw-r--r-- | drivers/nfc/pn533.c | 28 | ||||
-rw-r--r-- | drivers/nfc/pn544/i2c.c | 194 | ||||
-rw-r--r-- | drivers/nfc/pn544/pn544.c | 2 | ||||
-rw-r--r-- | drivers/nfc/pn544/pn544.h | 3 | ||||
-rw-r--r-- | drivers/nfc/port100.c | 25 | ||||
-rw-r--r-- | drivers/nfc/trf7970a.c | 1370 | ||||
-rw-r--r-- | include/net/nfc/digital.h | 7 | ||||
-rw-r--r-- | include/net/nfc/nfc.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/nfc.h | 9 | ||||
-rw-r--r-- | net/nfc/core.c | 10 | ||||
-rw-r--r-- | net/nfc/digital.h | 6 | ||||
-rw-r--r-- | net/nfc/digital_core.c | 67 | ||||
-rw-r--r-- | net/nfc/digital_technology.c | 247 | ||||
-rw-r--r-- | net/nfc/hci/llc.c | 4 | ||||
-rw-r--r-- | net/nfc/llcp_core.c | 16 | ||||
-rw-r--r-- | net/nfc/nci/core.c | 3 | ||||
-rw-r--r-- | net/nfc/nci/spi.c | 3 | ||||
-rw-r--r-- | net/nfc/netlink.c | 8 |
22 files changed, 1985 insertions, 68 deletions
diff --git a/Documentation/devicetree/bindings/net/nfc/trf7970a.txt b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt new file mode 100644 index 000000000000..8dd3ef7bc56b --- /dev/null +++ b/Documentation/devicetree/bindings/net/nfc/trf7970a.txt @@ -0,0 +1,34 @@ +* Texas Instruments TRF7970A RFID/NFC/15693 Transceiver + +Required properties: +- compatible: Should be "ti,trf7970a". +- spi-max-frequency: Maximum SPI frequency (<= 2000000). +- interrupt-parent: phandle of parent interrupt handler. +- interrupts: A single interrupt specifier. +- ti,enable-gpios: Two GPIO entries used for 'EN' and 'EN2' pins on the + TRF7970A. +- vin-supply: Regulator for supply voltage to VIN pin + +Optional SoC Specific Properties: +- pinctrl-names: Contains only one value - "default". +- pintctrl-0: Specifies the pin control groups used for this controller. + +Example (for ARM-based BeagleBone with TRF7970A on SPI1): + +&spi1 { + status = "okay"; + + nfc@0 { + compatible = "ti,trf7970a"; + reg = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&trf7970a_default>; + spi-max-frequency = <2000000>; + interrupt-parent = <&gpio2>; + interrupts = <14 0>; + ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>, + <&gpio2 5 GPIO_ACTIVE_LOW>; + vin-supply = <&ldo3_reg>; + status = "okay"; + }; +}; diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..ec12265ac67b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6067,6 +6067,7 @@ F: include/net/nfc/ F: include/uapi/linux/nfc.h F: drivers/nfc/ F: include/linux/platform_data/pn544.h +F: Documentation/devicetree/bindings/net/nfc/ NFS, SUNRPC, AND LOCKD CLIENTS M: Trond Myklebust <trond.myklebust@primarydata.com> diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index fe20e1cc0545..65d4ca19d132 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -26,6 +26,18 @@ config NFC_WILINK Say Y here to compile support for Texas Instrument's NFC WiLink driver into the kernel or say M to compile it as module. +config NFC_TRF7970A + tristate "Texas Instruments TRF7970a NFC driver" + depends on SPI && NFC_DIGITAL + help + This option enables the NFC driver for Texas Instruments' TRF7970a + device. Such device supports 5 different protocols: ISO14443A, + ISO14443B, FeLiCa, ISO15693 and ISO18000-3. + + Say Y here to compile support for TRF7970a into the kernel or + say M to compile it as a module. The module will be called + trf7970a.ko. + config NFC_MEI_PHY tristate "MEI bus NFC device support" depends on INTEL_MEI && NFC_HCI diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index 56ab822ba03d..ae42a3fa60c9 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o obj-$(CONFIG_NFC_SIM) += nfcsim.o obj-$(CONFIG_NFC_PORT100) += port100.o obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ +obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index cf1a87bb74f8..d46a700a9637 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -55,26 +55,14 @@ NFC_PROTO_NFC_DEP_MASK) static const struct usb_device_id pn533_table[] = { - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = PN533_VENDOR_ID, - .idProduct = PN533_PRODUCT_ID, - .driver_info = PN533_DEVICE_STD, - }, - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = SCM_VENDOR_ID, - .idProduct = SCL3711_PRODUCT_ID, - .driver_info = PN533_DEVICE_STD, - }, - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = SONY_VENDOR_ID, - .idProduct = PASORI_PRODUCT_ID, - .driver_info = PN533_DEVICE_PASORI, - }, - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = ACS_VENDOR_ID, - .idProduct = ACR122U_PRODUCT_ID, - .driver_info = PN533_DEVICE_ACR122U, - }, + { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID), + .driver_info = PN533_DEVICE_STD }, + { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID), + .driver_info = PN533_DEVICE_STD }, + { USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID), + .driver_info = PN533_DEVICE_PASORI }, + { USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID), + .driver_info = PN533_DEVICE_ACR122U }, { } }; MODULE_DEVICE_TABLE(usb, pn533_table); diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index d6185ff2f87b..f2acd85be86e 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -58,8 +58,19 @@ MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); #define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" +/* + * Exposed through the 4 most significant bytes + * from the HCI SW_VERSION first byte, a.k.a. + * SW RomLib. + */ +#define PN544_HW_VARIANT_C2 0xa +#define PN544_HW_VARIANT_C3 0xb + +#define PN544_FW_CMD_RESET 0x01 #define PN544_FW_CMD_WRITE 0x08 #define PN544_FW_CMD_CHECK 0x06 +#define PN544_FW_CMD_SECURE_WRITE 0x0C +#define PN544_FW_CMD_SECURE_CHUNK_WRITE 0x0D struct pn544_i2c_fw_frame_write { u8 cmd; @@ -88,13 +99,31 @@ struct pn544_i2c_fw_blob { u8 data[]; }; +struct pn544_i2c_fw_secure_frame { + u8 cmd; + u16 be_datalen; + u8 data[]; +} __packed; + +struct pn544_i2c_fw_secure_blob { + u64 header; + u8 data[]; +}; + #define PN544_FW_CMD_RESULT_TIMEOUT 0x01 #define PN544_FW_CMD_RESULT_BAD_CRC 0x02 #define PN544_FW_CMD_RESULT_ACCESS_DENIED 0x08 #define PN544_FW_CMD_RESULT_PROTOCOL_ERROR 0x0B #define PN544_FW_CMD_RESULT_INVALID_PARAMETER 0x11 +#define PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND 0x13 #define PN544_FW_CMD_RESULT_INVALID_LENGTH 0x18 +#define PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR 0x19 +#define PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR 0x1D +#define PN544_FW_CMD_RESULT_MEMORY_ERROR 0x20 +#define PN544_FW_CMD_RESULT_CHUNK_OK 0x21 #define PN544_FW_CMD_RESULT_WRITE_FAILED 0x74 +#define PN544_FW_CMD_RESULT_COMMAND_REJECTED 0xE0 +#define PN544_FW_CMD_RESULT_CHUNK_ERROR 0xE6 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) @@ -104,11 +133,17 @@ struct pn544_i2c_fw_blob { #define PN544_FW_I2C_WRITE_DATA_MAX_LEN MIN((PN544_FW_I2C_MAX_PAYLOAD -\ PN544_FW_I2C_WRITE_FRAME_HEADER_LEN),\ PN544_FW_WRITE_BUFFER_MAX_LEN) +#define PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN 3 +#define PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN (PN544_FW_I2C_MAX_PAYLOAD -\ + PN544_FW_SECURE_CHUNK_WRITE_HEADER_LEN) +#define PN544_FW_SECURE_FRAME_HEADER_LEN 3 +#define PN544_FW_SECURE_BLOB_HEADER_LEN 8 #define FW_WORK_STATE_IDLE 1 #define FW_WORK_STATE_START 2 #define FW_WORK_STATE_WAIT_WRITE_ANSWER 3 #define FW_WORK_STATE_WAIT_CHECK_ANSWER 4 +#define FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER 5 struct pn544_i2c_phy { struct i2c_client *i2c_dev; @@ -119,6 +154,8 @@ struct pn544_i2c_phy { unsigned int gpio_fw; unsigned int en_polarity; + u8 hw_variant; + struct work_struct fw_work; int fw_work_state; char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; @@ -127,6 +164,8 @@ struct pn544_i2c_phy { size_t fw_blob_size; const u8 *fw_blob_data; size_t fw_written; + size_t fw_size; + int fw_cmd_result; int powered; @@ -390,6 +429,8 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy) switch (response.status) { case 0: return 0; + case PN544_FW_CMD_RESULT_CHUNK_OK: + return response.status; case PN544_FW_CMD_RESULT_TIMEOUT: return -ETIMEDOUT; case PN544_FW_CMD_RESULT_BAD_CRC: @@ -400,9 +441,20 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy) return -EPROTO; case PN544_FW_CMD_RESULT_INVALID_PARAMETER: return -EINVAL; + case PN544_FW_CMD_RESULT_UNSUPPORTED_COMMAND: + return -ENOTSUPP; case PN544_FW_CMD_RESULT_INVALID_LENGTH: return -EBADMSG; + case PN544_FW_CMD_RESULT_CRYPTOGRAPHIC_ERROR: + return -ENOKEY; + case PN544_FW_CMD_RESULT_VERSION_CONDITIONS_ERROR: + return -EINVAL; + case PN544_FW_CMD_RESULT_MEMORY_ERROR: + return -ENOMEM; + case PN544_FW_CMD_RESULT_COMMAND_REJECTED: + return -EACCES; case PN544_FW_CMD_RESULT_WRITE_FAILED: + case PN544_FW_CMD_RESULT_CHUNK_ERROR: return -EIO; default: return -EIO; @@ -469,7 +521,8 @@ static struct nfc_phy_ops i2c_phy_ops = { .disable = pn544_hci_i2c_disable, }; -static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name) +static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name, + u8 hw_variant) { struct pn544_i2c_phy *phy = phy_id; @@ -477,6 +530,7 @@ static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name) strcpy(phy->firmware_name, firmware_name); + phy->hw_variant = hw_variant; phy->fw_work_state = FW_WORK_STATE_START; schedule_work(&phy->fw_work); @@ -598,12 +652,93 @@ static int pn544_hci_i2c_fw_write_chunk(struct pn544_i2c_phy *phy) return 0; } +static int pn544_hci_i2c_fw_secure_write_frame_cmd(struct pn544_i2c_phy *phy, + const u8 *data, u16 datalen) +{ + u8 buf[PN544_FW_I2C_MAX_PAYLOAD]; + struct pn544_i2c_fw_secure_frame *chunk; + int chunklen; + int r; + + if (datalen > PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN) + datalen = PN544_FW_SECURE_CHUNK_WRITE_DATA_MAX_LEN; + + chunk = (struct pn544_i2c_fw_secure_frame *) buf; + + chunk->cmd = PN544_FW_CMD_SECURE_CHUNK_WRITE; + + put_unaligned_be16(datalen, &chunk->be_datalen); + + memcpy(chunk->data, data, datalen); + + chunklen = sizeof(chunk->cmd) + sizeof(chunk->be_datalen) + datalen; + + r = i2c_master_send(phy->i2c_dev, buf, chunklen); + + if (r == chunklen) + return datalen; + else if (r < 0) + return r; + else + return -EIO; + +} + +static int pn544_hci_i2c_fw_secure_write_frame(struct pn544_i2c_phy *phy) +{ + struct pn544_i2c_fw_secure_frame *framep; + int r; + + framep = (struct pn544_i2c_fw_secure_frame *) phy->fw_blob_data; + if (phy->fw_written == 0) + phy->fw_blob_size = get_unaligned_be16(&framep->be_datalen) + + PN544_FW_SECURE_FRAME_HEADER_LEN; + + /* Only secure write command can be chunked*/ + if (phy->fw_blob_size > PN544_FW_I2C_MAX_PAYLOAD && + framep->cmd != PN544_FW_CMD_SECURE_WRITE) + return -EINVAL; + + /* The firmware also have other commands, we just send them directly */ + if (phy->fw_blob_size < PN544_FW_I2C_MAX_PAYLOAD) { + r = i2c_master_send(phy->i2c_dev, + (const char *) phy->fw_blob_data, phy->fw_blob_size); + + if (r == phy->fw_blob_size) + goto exit; + else if (r < 0) + return r; + else + return -EIO; + } + + r = pn544_hci_i2c_fw_secure_write_frame_cmd(phy, + phy->fw_blob_data + phy->fw_written, + phy->fw_blob_size - phy->fw_written); + if (r < 0) + return r; + +exit: + phy->fw_written += r; + phy->fw_work_state = FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER; + + /* SW reset command will not trig any response from PN544 */ + if (framep->cmd == PN544_FW_CMD_RESET) { + pn544_hci_i2c_enable_mode(phy, PN544_FW_MODE); + phy->fw_cmd_result = 0; + schedule_work(&phy->fw_work); + } + + return 0; +} + static void pn544_hci_i2c_fw_work(struct work_struct *work) { struct pn544_i2c_phy *phy = container_of(work, struct pn544_i2c_phy, fw_work); int r; struct pn544_i2c_fw_blob *blob; + struct pn544_i2c_fw_secure_blob *secure_blob; switch (phy->fw_work_state) { case FW_WORK_STATE_START: @@ -614,13 +749,29 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work) if (r < 0) goto exit_state_start; - blob = (struct pn544_i2c_fw_blob *) phy->fw->data; - phy->fw_blob_size = get_unaligned_be32(&blob->be_size); - phy->fw_blob_dest_addr = get_unaligned_be32(&blob->be_destaddr); - phy->fw_blob_data = blob->data; - phy->fw_written = 0; - r = pn544_hci_i2c_fw_write_chunk(phy); + + switch (phy->hw_variant) { + case PN544_HW_VARIANT_C2: + blob = (struct pn544_i2c_fw_blob *) phy->fw->data; + phy->fw_blob_size = get_unaligned_be32(&blob->be_size); + phy->fw_blob_dest_addr = get_unaligned_be32( + &blob->be_destaddr); + phy->fw_blob_data = blob->data; + + r = pn544_hci_i2c_fw_write_chunk(phy); + break; + case PN544_HW_VARIANT_C3: + secure_blob = (struct pn544_i2c_fw_secure_blob *) + phy->fw->data; + phy->fw_blob_data = secure_blob->data; + phy->fw_size = phy->fw->size; + r = pn544_hci_i2c_fw_secure_write_frame(phy); + break; + default: + r = -ENOTSUPP; + break; + } exit_state_start: if (r < 0) @@ -672,6 +823,35 @@ exit_state_wait_check_answer: pn544_hci_i2c_fw_work_complete(phy, r); break; + case FW_WORK_STATE_WAIT_SECURE_WRITE_ANSWER: + r = phy->fw_cmd_result; + if (r < 0) + goto exit_state_wait_secure_write_answer; + + if (r == PN544_FW_CMD_RESULT_CHUNK_OK) { + r = pn544_hci_i2c_fw_secure_write_frame(phy); + goto exit_state_wait_secure_write_answer; + } + + if (phy->fw_written == phy->fw_blob_size) { + secure_blob = (struct pn544_i2c_fw_secure_blob *) + (phy->fw_blob_data + phy->fw_blob_size); + phy->fw_size -= phy->fw_blob_size + + PN544_FW_SECURE_BLOB_HEADER_LEN; + if (phy->fw_size >= PN544_FW_SECURE_BLOB_HEADER_LEN + + PN544_FW_SECURE_FRAME_HEADER_LEN) { + phy->fw_blob_data = secure_blob->data; + + phy->fw_written = 0; + r = pn544_hci_i2c_fw_secure_write_frame(phy); + } + } + +exit_state_wait_secure_write_answer: + if (r < 0 || phy->fw_size == 0) + pn544_hci_i2c_fw_work_complete(phy, r); + break; + default: break; } diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 3df4a109cfad..9c8051d20cea 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -786,7 +786,7 @@ static int pn544_hci_fw_download(struct nfc_hci_dev *hdev, if (info->fw_download == NULL) return -ENOTSUPP; - return info->fw_download(info->phy_id, firmware_name); + return info->fw_download(info->phy_id, firmware_name, hdev->sw_romlib); } static int pn544_hci_discover_se(struct nfc_hci_dev *hdev) diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h index 491bf45da358..2aa9233e8086 100644 --- a/drivers/nfc/pn544/pn544.h +++ b/drivers/nfc/pn544/pn544.h @@ -25,7 +25,8 @@ #define PN544_HCI_MODE 0 #define PN544_FW_MODE 1 -typedef int (*fw_download_t)(void *context, const char *firmware_name); +typedef int (*fw_download_t)(void *context, const char *firmware_name, + u8 hw_variant); int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name, int phy_headroom, int phy_tailroom, int phy_payload, diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c index a8555f81cbba..b7a372af5eb7 100644 --- a/drivers/nfc/port100.c +++ b/drivers/nfc/port100.c @@ -27,7 +27,8 @@ #define PORT100_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ NFC_PROTO_MIFARE_MASK | \ NFC_PROTO_FELICA_MASK | \ - NFC_PROTO_NFC_DEP_MASK) + NFC_PROTO_NFC_DEP_MASK | \ + NFC_PROTO_ISO14443_MASK) #define PORT100_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \ NFC_DIGITAL_DRV_CAPS_TG_CRC) @@ -139,6 +140,8 @@ static const struct port100_in_rf_setting in_rf_settings[] = { .in_recv_set_number = 15, .in_recv_comm_type = PORT100_COMM_TYPE_IN_106A, }, + /* Ensures the array has NFC_DIGITAL_RF_TECH_LAST elements */ + [NFC_DIGITAL_RF_TECH_LAST] = { 0 }, }; /** @@ -174,6 +177,9 @@ static const struct port100_tg_rf_setting tg_rf_settings[] = { .tg_set_number = 8, .tg_comm_type = PORT100_COMM_TYPE_TG_424F, }, + /* Ensures the array has NFC_DIGITAL_RF_TECH_LAST elements */ + [NFC_DIGITAL_RF_TECH_LAST] = { 0 }, + }; #define PORT100_IN_PROT_INITIAL_GUARD_TIME 0x00 @@ -293,6 +299,10 @@ in_protocols[][PORT100_IN_MAX_NUM_PROTOCOLS + 1] = { { PORT100_IN_PROT_CHECK_CRC, 0 }, { PORT100_IN_PROT_END, 0 }, }, + [NFC_DIGITAL_FRAMING_NFCA_T4T] = { + /* nfc_digital_framing_nfca_standard_with_crc_a */ + { PORT100_IN_PROT_END, 0 }, + }, [NFC_DIGITAL_FRAMING_NFCA_NFC_DEP] = { /* nfc_digital_framing_nfca_standard */ { PORT100_IN_PROT_END, 0 }, @@ -330,6 +340,10 @@ in_protocols[][PORT100_IN_MAX_NUM_PROTOCOLS + 1] = { [NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED] = { { PORT100_IN_PROT_END, 0 }, }, + /* Ensures the array has NFC_DIGITAL_FRAMING_LAST elements */ + [NFC_DIGITAL_FRAMING_LAST] = { + { PORT100_IN_PROT_END, 0 }, + }, }; static struct port100_protocol @@ -371,6 +385,10 @@ tg_protocols[][PORT100_TG_MAX_NUM_PROTOCOLS + 1] = { { PORT100_TG_PROT_RF_OFF, 1 }, { PORT100_TG_PROT_END, 0 }, }, + /* Ensures the array has NFC_DIGITAL_FRAMING_LAST elements */ + [NFC_DIGITAL_FRAMING_LAST] = { + { PORT100_TG_PROT_END, 0 }, + }, }; struct port100 { @@ -1356,10 +1374,7 @@ static struct nfc_digital_ops port100_digital_ops = { }; static const struct usb_device_id port100_table[] = { - { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, - .idVendor = SONY_VENDOR_ID, - .idProduct = RCS380_PRODUCT_ID, - }, + { USB_DEVICE(SONY_VENDOR_ID, RCS380_PRODUCT_ID), }, { } }; MODULE_DEVICE_TABLE(usb, port100_table); diff --git a/drivers/nfc/trf7970a.c b/drivers/nfc/trf7970a.c new file mode 100644 index 000000000000..d9babe986473 --- /dev/null +++ b/drivers/nfc/trf7970a.c @@ -0,0 +1,1370 @@ +/* + * TI TRF7970a RFID/NFC Transceiver Driver + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: Erick Macias <emacias@ti.com> + * Author: Felipe Balbi <balbi@ti.com> + * Author: Mark A. Greer <mgreer@animalcreek.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/netdevice.h> +#include <linux/interrupt.h> +#include <linux/nfc.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> + +#include <net/nfc/nfc.h> +#include <net/nfc/digital.h> + +/* There are 3 ways the host can communicate with the trf7970a: + * parallel mode, SPI with Slave Select (SS) mode, and SPI without + * SS mode. The driver only supports the two SPI modes. + * + * The trf7970a is very timing sensitive and the VIN, EN2, and EN + * pins must asserted in that order and with specific delays in between. + * The delays used in the driver were provided by TI and have been + * confirmed to work with this driver. + * + * Timeouts are implemented using the delayed workqueue kernel facility. + * Timeouts are required so things don't hang when there is no response + * from the trf7970a (or tag). Using this mechanism creates a race with + * interrupts, however. That is, an interrupt and a timeout could occur + * closely enough together that one is blocked by the mutex while the other + * executes. When the timeout handler executes first and blocks the + * interrupt handler, it will eventually set the state to IDLE so the + * interrupt handler will check the state and exit with no harm done. + * When the interrupt handler executes first and blocks the timeout handler, + * the cancel_delayed_work() call will know that it didn't cancel the + * work item (i.e., timeout) and will return zero. That return code is + * used by the timer handler to indicate that it should ignore the timeout + * once its unblocked. + * + * Aborting an active command isn't as simple as it seems because the only + * way to abort a command that's already been sent to the tag is so turn + * off power to the tag. If we do that, though, we'd have to go through + * the entire anticollision procedure again but the digital layer doesn't + * support that. So, if an abort is received before trf7970a_in_send_cmd() + * has sent the command to the tag, it simply returns -ECANCELED. If the + * command has already been sent to the tag, then the driver continues + * normally and recieves the response data (or error) but just before + * sending the data upstream, it frees the rx_skb and sends -ECANCELED + * upstream instead. If the command failed, that error will be sent + * upstream. + * + * When recieving data from a tag and the interrupt status register has + * only the SRX bit set, it means that all of the data has been received + * (once what's in the fifo has been read). However, depending on timing + * an interrupt status with only the SRX bit set may not be recived. In + * those cases, the timeout mechanism is used to wait 5 ms in case more + * data arrives. After 5 ms, it is assumed that all of the data has been + * received and the accumulated rx data is sent upstream. The + * 'TRF7970A_ST_WAIT_FOR_RX_DATA_CONT' state is used for this purpose + * (i.e., it indicates that some data has been received but we're not sure + * if there is more coming so a timeout in this state means all data has + * been received and there isn't an error). The delay is 5 ms since delays + * over 2 ms have been observed during testing (a little extra just in case). + * + * Type 2 write and sector select commands respond with a 4-bit ACK or NACK. + * Having only 4 bits in the FIFO won't normally generate an interrupt so + * driver enables the '4_bit_RX' bit of the Special Functions register 1 + * to cause an interrupt in that case. Leaving that bit for a read command + * messes up the data returned so it is only enabled when the framing is + * 'NFC_DIGITAL_FRAMING_NFCA_T2T' and the command is not a read command. + * Unfortunately, that means that the driver has to peek into tx frames + * when the framing is 'NFC_DIGITAL_FRAMING_NFCA_T2T'. This is done by + * the trf7970a_per_cmd_config() routine. + * + * ISO/IEC 15693 frames specify whether to use single or double sub-carrier + * frequencies and whether to use low or high data rates in the flags byte + * of the frame. This means that the driver has to peek at all 15693 frames + * to determine what speed to set the communication to. In addition, write + * and lock commands use the OPTION flag to indicate that an EOF must be + * sent to the tag before it will send its response. So the driver has to + * examine all frames for that reason too. + * + * It is unclear how long to wait before sending the EOF. According to the + * Note under Table 1-1 in section 1.6 of + * http://www.ti.com/lit/ug/scbu011/scbu011.pdf, that wait should be at least + * 10 ms for TI Tag-it HF-I tags; however testing has shown that is not long + * enough. For this reason, the driver waits 20 ms which seems to work + * reliably. + */ + +#define TRF7970A_SUPPORTED_PROTOCOLS \ + (NFC_PROTO_MIFARE_MASK | NFC_PROTO_ISO14443_MASK | \ + NFC_PROTO_ISO15693_MASK) + +/* TX data must be prefixed with a FIFO reset cmd, a cmd that depends + * on what the current framing is, the address of the TX length byte 1 + * register (0x1d), and the 2 byte length of the data to be transmitted. + * That totals 5 bytes. + */ +#define TRF7970A_TX_SKB_HEADROOM 5 + +#define TRF7970A_RX_SKB_ALLOC_SIZE 256 + +#define TRF7970A_FIFO_SIZE 128 + +/* TX length is 3 nibbles long ==> 4KB - 1 bytes max */ +#define TRF7970A_TX_MAX (4096 - 1) + +#define TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT 5 +#define TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT 3 +#define TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF 20 + +/* Quirks */ +/* Erratum: When reading IRQ Status register on trf7970a, we must issue a + * read continuous command for IRQ Status and Collision Position registers. + */ +#define TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA BIT(0) + +/* Direct commands */ +#define TRF7970A_CMD_IDLE 0x00 +#define TRF7970A_CMD_SOFT_INIT 0x03 +#define TRF7970A_CMD_RF_COLLISION 0x04 +#define TRF7970A_CMD_RF_COLLISION_RESPONSE_N 0x05 +#define TRF7970A_CMD_RF_COLLISION_RESPONSE_0 0x06 +#define TRF7970A_CMD_FIFO_RESET 0x0f +#define TRF7970A_CMD_TRANSMIT_NO_CRC 0x10 +#define TRF7970A_CMD_TRANSMIT 0x11 +#define TRF7970A_CMD_DELAY_TRANSMIT_NO_CRC 0x12 +#define TRF7970A_CMD_DELAY_TRANSMIT 0x13 +#define TRF7970A_CMD_EOF 0x14 +#define TRF7970A_CMD_CLOSE_SLOT 0x15 +#define TRF7970A_CMD_BLOCK_RX 0x16 +#define TRF7970A_CMD_ENABLE_RX 0x17 +#define TRF7970A_CMD_TEST_EXT_RF 0x18 +#define TRF7970A_CMD_TEST_INT_RF 0x19 +#define TRF7970A_CMD_RX_GAIN_ADJUST 0x1a + +/* Bits determining whether its a direct command or register R/W, + * whether to use a continuous SPI transaction or not, and the actual + * direct cmd opcode or regster address. + */ +#define TRF7970A_CMD_BIT_CTRL BIT(7) +#define TRF7970A_CMD_BIT_RW BIT(6) +#define TRF7970A_CMD_BIT_CONTINUOUS BIT(5) +#define TRF7970A_CMD_BIT_OPCODE(opcode) ((opcode) & 0x1f) + +/* Registers addresses */ +#define TRF7970A_CHIP_STATUS_CTRL 0x00 +#define TRF7970A_ISO_CTRL 0x01 +#define TRF7970A_ISO14443B_TX_OPTIONS 0x02 +#define TRF7970A_ISO14443A_HIGH_BITRATE_OPTIONS 0x03 +#define TRF7970A_TX_TIMER_SETTING_H_BYTE 0x04 +#define TRF7970A_TX_TIMER_SETTING_L_BYTE 0x05 +#define TRF7970A_TX_PULSE_LENGTH_CTRL 0x06 +#define TRF7970A_RX_NO_RESPONSE_WAIT 0x07 +#define TRF7970A_RX_WAIT_TIME 0x08 +#define TRF7970A_MODULATOR_SYS_CLK_CTRL 0x09 +#define TRF7970A_RX_SPECIAL_SETTINGS 0x0a +#define TRF7970A_REG_IO_CTRL 0x0b +#define TRF7970A_IRQ_STATUS 0x0c +#define TRF7970A_COLLISION_IRQ_MASK 0x0d +#define TRF7970A_COLLISION_POSITION 0x0e +#define TRF7970A_RSSI_OSC_STATUS 0x0f +#define TRF7970A_SPECIAL_FCN_REG1 0x10 +#define TRF7970A_SPECIAL_FCN_REG2 0x11 +#define TRF7970A_RAM1 0x12 +#define TRF7970A_RAM2 0x13 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS 0x14 +#define TRF7970A_NFC_LOW_FIELD_LEVEL 0x16 +#define TRF7970A_NFCID1 0x17 +#define TRF7970A_NFC_TARGET_LEVEL 0x18 +#define TRF79070A_NFC_TARGET_PROTOCOL 0x19 +#define TRF7970A_TEST_REGISTER1 0x1a +#define TRF7970A_TEST_REGISTER2 0x1b +#define TRF7970A_FIFO_STATUS 0x1c +#define TRF7970A_TX_LENGTH_BYTE1 0x1d +#define TRF7970A_TX_LENGTH_BYTE2 0x1e +#define TRF7970A_FIFO_IO_REGISTER 0x1f + +/* Chip Status Control Register Bits */ +#define TRF7970A_CHIP_STATUS_VRS5_3 BIT(0) +#define TRF7970A_CHIP_STATUS_REC_ON BIT(1) +#define TRF7970A_CHIP_STATUS_AGC_ON BIT(2) +#define TRF7970A_CHIP_STATUS_PM_ON BIT(3) +#define TRF7970A_CHIP_STATUS_RF_PWR BIT(4) +#define TRF7970A_CHIP_STATUS_RF_ON BIT(5) +#define TRF7970A_CHIP_STATUS_DIRECT BIT(6) +#define TRF7970A_CHIP_STATUS_STBY BIT(7) + +/* ISO Control Register Bits */ +#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_662 0x00 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_662 0x01 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648 0x02 +#define TRF7970A_ISO_CTRL_15693_SGL_1OF256_2648 0x03 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a 0x04 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_667 0x05 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669 0x06 +#define TRF7970A_ISO_CTRL_15693_DBL_1OF256_2669 0x07 +#define TRF7970A_ISO_CTRL_14443A_106 0x08 +#define TRF7970A_ISO_CTRL_14443A_212 0x09 +#define TRF7970A_ISO_CTRL_14443A_424 0x0a +#define TRF7970A_ISO_CTRL_14443A_848 0x0b +#define TRF7970A_ISO_CTRL_14443B_106 0x0c +#define TRF7970A_ISO_CTRL_14443B_212 0x0d +#define TRF7970A_ISO_CTRL_14443B_424 0x0e +#define TRF7970A_ISO_CTRL_14443B_848 0x0f +#define TRF7970A_ISO_CTRL_FELICA_212 0x1a +#define TRF7970A_ISO_CTRL_FELICA_424 0x1b +#define TRF7970A_ISO_CTRL_RFID BIT(5) +#define TRF7970A_ISO_CTRL_DIR_MODE BIT(6) +#define TRF7970A_ISO_CTRL_RX_CRC_N BIT(7) /* true == No CRC */ + +#define TRF7970A_ISO_CTRL_RFID_SPEED_MASK 0x1f + +/* Modulator and SYS_CLK Control Register Bits */ +#define TRF7970A_MODULATOR_DEPTH(n) ((n) & 0x7) +#define TRF7970A_MODULATOR_DEPTH_ASK10 (TRF7970A_MODULATOR_DEPTH(0)) +#define TRF7970A_MODULATOR_DEPTH_OOK (TRF7970A_MODULATOR_DEPTH(1)) +#define TRF7970A_MODULATOR_DEPTH_ASK7 (TRF7970A_MODULATOR_DEPTH(2)) +#define TRF7970A_MODULATOR_DEPTH_ASK8_5 (TRF7970A_MODULATOR_DEPTH(3)) +#define TRF7970A_MODULATOR_DEPTH_ASK13 (TRF7970A_MODULATOR_DEPTH(4)) +#define TRF7970A_MODULATOR_DEPTH_ASK16 (TRF7970A_MODULATOR_DEPTH(5)) +#define TRF7970A_MODULATOR_DEPTH_ASK22 (TRF7970A_MODULATOR_DEPTH(6)) +#define TRF7970A_MODULATOR_DEPTH_ASK30 (TRF7970A_MODULATOR_DEPTH(7)) +#define TRF7970A_MODULATOR_EN_ANA BIT(3) +#define TRF7970A_MODULATOR_CLK(n) (((n) & 0x3) << 4) +#define TRF7970A_MODULATOR_CLK_DISABLED (TRF7970A_MODULATOR_CLK(0)) +#define TRF7970A_MODULATOR_CLK_3_6 (TRF7970A_MODULATOR_CLK(1)) +#define TRF7970A_MODULATOR_CLK_6_13 (TRF7970A_MODULATOR_CLK(2)) +#define TRF7970A_MODULATOR_CLK_13_27 (TRF7970A_MODULATOR_CLK(3)) +#define TRF7970A_MODULATOR_EN_OOK BIT(6) +#define TRF7970A_MODULATOR_27MHZ BIT(7) + +/* IRQ Status Register Bits */ +#define TRF7970A_IRQ_STATUS_NORESP BIT(0) /* ISO15693 only */ +#define TRF7970A_IRQ_STATUS_COL BIT(1) +#define TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR BIT(2) +#define TRF7970A_IRQ_STATUS_PARITY_ERROR BIT(3) +#define TRF7970A_IRQ_STATUS_CRC_ERROR BIT(4) +#define TRF7970A_IRQ_STATUS_FIFO BIT(5) +#define TRF7970A_IRQ_STATUS_SRX BIT(6) +#define TRF7970A_IRQ_STATUS_TX BIT(7) + +#define TRF7970A_IRQ_STATUS_ERROR \ + (TRF7970A_IRQ_STATUS_COL | \ + TRF7970A_IRQ_STATUS_FRAMING_EOF_ERROR | \ + TRF7970A_IRQ_STATUS_PARITY_ERROR | \ + TRF7970A_IRQ_STATUS_CRC_ERROR) + +#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0) +#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1) +#define TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX BIT(2) +#define TRF7970A_SPECIAL_FCN_REG1_SP_DIR_MODE BIT(3) +#define TRF7970A_SPECIAL_FCN_REG1_NEXT_SLOT_37US BIT(4) +#define TRF7970A_SPECIAL_FCN_REG1_PAR43 BIT(5) + +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_124 (0x0 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_120 (0x1 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_112 (0x2 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 (0x3 << 2) +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_4 0x0 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_8 0x1 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_16 0x2 +#define TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32 0x3 + +#define TRF7970A_FIFO_STATUS_OVERFLOW BIT(7) + +/* NFC (ISO/IEC 14443A) Type 2 Tag commands */ +#define NFC_T2T_CMD_READ 0x30 + +/* ISO 15693 commands codes */ +#define ISO15693_CMD_INVENTORY 0x01 +#define ISO15693_CMD_READ_SINGLE_BLOCK 0x20 +#define ISO15693_CMD_WRITE_SINGLE_BLOCK 0x21 +#define ISO15693_CMD_LOCK_BLOCK 0x22 +#define ISO15693_CMD_READ_MULTIPLE_BLOCK 0x23 +#define ISO15693_CMD_WRITE_MULTIPLE_BLOCK 0x24 +#define ISO15693_CMD_SELECT 0x25 +#define ISO15693_CMD_RESET_TO_READY 0x26 +#define ISO15693_CMD_WRITE_AFI 0x27 +#define ISO15693_CMD_LOCK_AFI 0x28 +#define ISO15693_CMD_WRITE_DSFID 0x29 +#define ISO15693_CMD_LOCK_DSFID 0x2a +#define ISO15693_CMD_GET_SYSTEM_INFO 0x2b +#define ISO15693_CMD_GET_MULTIPLE_BLOCK_SECURITY_STATUS 0x2c + +/* ISO 15693 request and response flags */ +#define ISO15693_REQ_FLAG_SUB_CARRIER BIT(0) +#define ISO15693_REQ_FLAG_DATA_RATE BIT(1) +#define ISO15693_REQ_FLAG_INVENTORY BIT(2) +#define ISO15693_REQ_FLAG_PROTOCOL_EXT BIT(3) +#define ISO15693_REQ_FLAG_SELECT BIT(4) +#define ISO15693_REQ_FLAG_AFI BIT(4) +#define ISO15693_REQ_FLAG_ADDRESS BIT(5) +#define ISO15693_REQ_FLAG_NB_SLOTS BIT(5) +#define ISO15693_REQ_FLAG_OPTION BIT(6) + +#define ISO15693_REQ_FLAG_SPEED_MASK \ + (ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE) + +enum trf7970a_state { + TRF7970A_ST_OFF, + TRF7970A_ST_IDLE, + TRF7970A_ST_IDLE_RX_BLOCKED, + TRF7970A_ST_WAIT_FOR_TX_FIFO, + TRF7970A_ST_WAIT_FOR_RX_DATA, + TRF7970A_ST_WAIT_FOR_RX_DATA_CONT, + TRF7970A_ST_WAIT_TO_ISSUE_EOF, + TRF7970A_ST_MAX +}; + +struct trf7970a { + enum trf7970a_state state; + struct device *dev; + struct spi_device *spi; + struct regulator *regulator; + struct nfc_digital_dev *ddev; + u32 quirks; + bool powering_up; + bool aborting; + struct sk_buff *tx_skb; + struct sk_buff *rx_skb; + nfc_digital_cmd_complete_t cb; + void *cb_arg; + u8 iso_ctrl; + u8 special_fcn_reg1; + int technology; + int framing; + u8 tx_cmd; + bool issue_eof; + int en2_gpio; + int en_gpio; + struct mutex lock; + unsigned int timeout; + bool ignore_timeout; + struct delayed_work timeout_work; +}; + + +static int trf7970a_cmd(struct trf7970a *trf, u8 opcode) +{ + u8 cmd = TRF7970A_CMD_BIT_CTRL | TRF7970A_CMD_BIT_OPCODE(opcode); + int ret; + + dev_dbg(trf->dev, "cmd: 0x%x\n", cmd); + + ret = spi_write(trf->spi, &cmd, 1); + if (ret) + dev_err(trf->dev, "%s - cmd: 0x%x, ret: %d\n", __func__, cmd, + ret); + return ret; +} + +static int trf7970a_read(struct trf7970a *trf, u8 reg, u8 *val) +{ + u8 addr = TRF7970A_CMD_BIT_RW | reg; + int ret; + + ret = spi_write_then_read(trf->spi, &addr, 1, val, 1); + if (ret) + dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, + ret); + + dev_dbg(trf->dev, "read(0x%x): 0x%x\n", addr, *val); + + return ret; +} + +static int trf7970a_read_cont(struct trf7970a *trf, u8 reg, + u8 *buf, size_t len) +{ + u8 addr = reg | TRF7970A_CMD_BIT_RW | TRF7970A_CMD_BIT_CONTINUOUS; + int ret; + + dev_dbg(trf->dev, "read_cont(0x%x, %zd)\n", addr, len); + + ret = spi_write_then_read(trf->spi, &addr, 1, buf, len); + if (ret) + dev_err(trf->dev, "%s - addr: 0x%x, ret: %d\n", __func__, addr, + ret); + return ret; +} + +static int trf7970a_write(struct trf7970a *trf, u8 reg, u8 val) +{ + u8 buf[2] = { reg, val }; + int ret; + + dev_dbg(trf->dev, "write(0x%x): 0x%x\n", reg, val); + + ret = spi_write(trf->spi, buf, 2); + if (ret) + dev_err(trf->dev, "%s - write: 0x%x 0x%x, ret: %d\n", __func__, + buf[0], buf[1], ret); + + return ret; +} + +static int trf7970a_read_irqstatus(struct trf7970a *trf, u8 *status) +{ + int ret; + u8 buf[2]; + u8 addr; + + addr = TRF7970A_IRQ_STATUS | TRF7970A_CMD_BIT_RW; + + if (trf->quirks & TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA) { + addr |= TRF7970A_CMD_BIT_CONTINUOUS; + ret = spi_write_then_read(trf->spi, &addr, 1, buf, 2); + } else { + ret = spi_write_then_read(trf->spi, &addr, 1, buf, 1); + } + + if (ret) + dev_err(trf->dev, "%s - irqstatus: Status read failed: %d\n", + __func__, ret); + else + *status = buf[0]; + + return ret; +} + +static void trf7970a_send_upstream(struct trf7970a *trf) +{ + u8 rssi; + + dev_kfree_skb_any(trf->tx_skb); + trf->tx_skb = NULL; + + if (trf->rx_skb && !IS_ERR(trf->rx_skb) && !trf->aborting) + print_hex_dump_debug("trf7970a rx data: ", DUMP_PREFIX_NONE, + 16, 1, trf->rx_skb->data, trf->rx_skb->len, + false); + + /* According to the manual it is "good form" to reset the fifo and + * read the RSSI levels & oscillator status register here. It doesn't + * explain why. + */ + trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + trf7970a_read(trf, TRF7970A_RSSI_OSC_STATUS, &rssi); + + trf->state = TRF7970A_ST_IDLE; + + if (trf->aborting) { + dev_dbg(trf->dev, "Abort process complete\n"); + + if (!IS_ERR(trf->rx_skb)) { + kfree_skb(trf->rx_skb); + trf->rx_skb = ERR_PTR(-ECANCELED); + } + + trf->aborting = false; + } + + trf->cb(trf->ddev, trf->cb_arg, trf->rx_skb); + + trf->rx_skb = NULL; +} + +static void trf7970a_send_err_upstream(struct trf7970a *trf, int errno) +{ + dev_dbg(trf->dev, "Error - state: %d, errno: %d\n", trf->state, errno); + + kfree_skb(trf->rx_skb); + trf->rx_skb = ERR_PTR(errno); + + trf7970a_send_upstream(trf); +} + +static int trf7970a_transmit(struct trf7970a *trf, struct sk_buff *skb, + unsigned int len) +{ + unsigned int timeout; + int ret; + + print_hex_dump_debug("trf7970a tx data: ", DUMP_PREFIX_NONE, + 16, 1, skb->data, len, false); + + ret = spi_write(trf->spi, skb->data, len); + if (ret) { + dev_err(trf->dev, "%s - Can't send tx data: %d\n", __func__, + ret); + return ret; + } + + skb_pull(skb, len); + + if (skb->len > 0) { + trf->state = TRF7970A_ST_WAIT_FOR_TX_FIFO; + timeout = TRF7970A_WAIT_FOR_FIFO_DRAIN_TIMEOUT; + } else { + if (trf->issue_eof) { + trf->state = TRF7970A_ST_WAIT_TO_ISSUE_EOF; + timeout = TRF7970A_WAIT_TO_ISSUE_ISO15693_EOF; + } else { + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; + timeout = trf->timeout; + } + } + + dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", timeout, + trf->state); + + schedule_delayed_work(&trf->timeout_work, msecs_to_jiffies(timeout)); + + return 0; +} + +static void trf7970a_fill_fifo(struct trf7970a *trf) +{ + struct sk_buff *skb = trf->tx_skb; + unsigned int len; + int ret; + u8 fifo_bytes; + + ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + dev_dbg(trf->dev, "Filling FIFO - fifo_bytes: 0x%x\n", fifo_bytes); + + if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) { + dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__, + fifo_bytes); + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + /* Calculate how much more data can be written to the fifo */ + len = TRF7970A_FIFO_SIZE - fifo_bytes; + len = min(skb->len, len); + + ret = trf7970a_transmit(trf, skb, len); + if (ret) + trf7970a_send_err_upstream(trf, ret); +} + +static void trf7970a_drain_fifo(struct trf7970a *trf, u8 status) +{ + struct sk_buff *skb = trf->rx_skb; + int ret; + u8 fifo_bytes; + + if (status & TRF7970A_IRQ_STATUS_ERROR) { + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + ret = trf7970a_read(trf, TRF7970A_FIFO_STATUS, &fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + dev_dbg(trf->dev, "Draining FIFO - fifo_bytes: 0x%x\n", fifo_bytes); + + if (!fifo_bytes) + goto no_rx_data; + + if (fifo_bytes & TRF7970A_FIFO_STATUS_OVERFLOW) { + dev_err(trf->dev, "%s - fifo overflow: 0x%x\n", __func__, + fifo_bytes); + trf7970a_send_err_upstream(trf, -EIO); + return; + } + + if (fifo_bytes > skb_tailroom(skb)) { + skb = skb_copy_expand(skb, skb_headroom(skb), + max_t(int, fifo_bytes, + TRF7970A_RX_SKB_ALLOC_SIZE), + GFP_KERNEL); + if (!skb) { + trf7970a_send_err_upstream(trf, -ENOMEM); + return; + } + + kfree_skb(trf->rx_skb); + trf->rx_skb = skb; + } + + ret = trf7970a_read_cont(trf, TRF7970A_FIFO_IO_REGISTER, + skb_put(skb, fifo_bytes), fifo_bytes); + if (ret) { + trf7970a_send_err_upstream(trf, ret); + return; + } + + /* If received Type 2 ACK/NACK, shift right 4 bits and pass up */ + if ((trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T) && (skb->len == 1) && + (trf->special_fcn_reg1 == + TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX)) { + skb->data[0] >>= 4; + status = TRF7970A_IRQ_STATUS_SRX; + } else { + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA_CONT; + } + +no_rx_data: + if (status == TRF7970A_IRQ_STATUS_SRX) { /* Receive complete */ + trf7970a_send_upstream(trf); + return; + } + + dev_dbg(trf->dev, "Setting timeout for %d ms\n", + TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT); + + schedule_delayed_work(&trf->timeout_work, + msecs_to_jiffies(TRF7970A_WAIT_FOR_RX_DATA_TIMEOUT)); +} + +static irqreturn_t trf7970a_irq(int irq, void *dev_id) +{ + struct trf7970a *trf = dev_id; + int ret; + u8 status; + + mutex_lock(&trf->lock); + + if (trf->state == TRF7970A_ST_OFF) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + ret = trf7970a_read_irqstatus(trf, &status); + if (ret) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + dev_dbg(trf->dev, "IRQ - state: %d, status: 0x%x\n", trf->state, + status); + + if (!status) { + mutex_unlock(&trf->lock); + return IRQ_NONE; + } + + switch (trf->state) { + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + /* If getting interrupts caused by RF noise, turn off the + * receiver to avoid unnecessary interrupts. It will be + * turned back on in trf7970a_in_send_cmd() when the next + * command is issued. + */ + if (status & TRF7970A_IRQ_STATUS_ERROR) { + trf7970a_cmd(trf, TRF7970A_CMD_BLOCK_RX); + trf->state = TRF7970A_ST_IDLE_RX_BLOCKED; + } + + trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + break; + case TRF7970A_ST_WAIT_FOR_TX_FIFO: + if (status & TRF7970A_IRQ_STATUS_TX) { + trf->ignore_timeout = + !cancel_delayed_work(&trf->timeout_work); + trf7970a_fill_fifo(trf); + } else { + trf7970a_send_err_upstream(trf, -EIO); + } + break; + case TRF7970A_ST_WAIT_FOR_RX_DATA: + case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: + if (status & TRF7970A_IRQ_STATUS_SRX) { + trf->ignore_timeout = + !cancel_delayed_work(&trf->timeout_work); + trf7970a_drain_fifo(trf, status); + } else if (!(status & TRF7970A_IRQ_STATUS_TX)) { + trf7970a_send_err_upstream(trf, -EIO); + } + break; + case TRF7970A_ST_WAIT_TO_ISSUE_EOF: + if (status != TRF7970A_IRQ_STATUS_TX) + trf7970a_send_err_upstream(trf, -EIO); + break; + default: + dev_err(trf->dev, "%s - Driver in invalid state: %d\n", + __func__, trf->state); + } + + mutex_unlock(&trf->lock); + return IRQ_HANDLED; +} + +static void trf7970a_issue_eof(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Issuing EOF\n"); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_FIFO_RESET); + if (ret) + trf7970a_send_err_upstream(trf, ret); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_EOF); + if (ret) + trf7970a_send_err_upstream(trf, ret); + + trf->state = TRF7970A_ST_WAIT_FOR_RX_DATA; + + dev_dbg(trf->dev, "Setting timeout for %d ms, state: %d\n", + trf->timeout, trf->state); + + schedule_delayed_work(&trf->timeout_work, + msecs_to_jiffies(trf->timeout)); +} + +static void trf7970a_timeout_work_handler(struct work_struct *work) +{ + struct trf7970a *trf = container_of(work, struct trf7970a, + timeout_work.work); + + dev_dbg(trf->dev, "Timeout - state: %d, ignore_timeout: %d\n", + trf->state, trf->ignore_timeout); + + mutex_lock(&trf->lock); + + if (trf->ignore_timeout) + trf->ignore_timeout = false; + else if (trf->state == TRF7970A_ST_WAIT_FOR_RX_DATA_CONT) + trf7970a_send_upstream(trf); /* No more rx data so send up */ + else if (trf->state == TRF7970A_ST_WAIT_TO_ISSUE_EOF) + trf7970a_issue_eof(trf); + else + trf7970a_send_err_upstream(trf, -ETIMEDOUT); + + mutex_unlock(&trf->lock); +} + +static int trf7970a_init(struct trf7970a *trf) +{ + int ret; + + dev_dbg(trf->dev, "Initializing device - state: %d\n", trf->state); + + ret = trf7970a_cmd(trf, TRF7970A_CMD_SOFT_INIT); + if (ret) + goto err_out; + + ret = trf7970a_cmd(trf, TRF7970A_CMD_IDLE); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_MODULATOR_SYS_CLK_CTRL, + TRF7970A_MODULATOR_DEPTH_OOK); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS, + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLH_96 | + TRF7970A_ADJUTABLE_FIFO_IRQ_LEVELS_WLL_32); + if (ret) + goto err_out; + + ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, 0); + if (ret) + goto err_out; + + trf->special_fcn_reg1 = 0; + + ret = trf7970a_write(trf, TRF7970A_CHIP_STATUS_CTRL, + TRF7970A_CHIP_STATUS_RF_ON | + TRF7970A_CHIP_STATUS_VRS5_3); + if (ret) + goto err_out; + + return 0; + +err_out: + dev_dbg(trf->dev, "Couldn't init device: %d\n", ret); + return ret; +} + +static void trf7970a_switch_rf_off(struct trf7970a *trf) +{ + dev_dbg(trf->dev, "Switching rf off\n"); + + gpio_set_value(trf->en_gpio, 0); + gpio_set_value(trf->en2_gpio, 0); + + trf->aborting = false; + trf->state = TRF7970A_ST_OFF; +} + +static int trf7970a_switch_rf_on(struct trf7970a *trf) +{ + unsigned long delay; + int ret; + + dev_dbg(trf->dev, "Switching rf on\n"); + + if (trf->powering_up) + usleep_range(5000, 6000); + + gpio_set_value(trf->en2_gpio, 1); + usleep_range(1000, 2000); + gpio_set_value(trf->en_gpio, 1); + + /* The delay between enabling the trf7970a and issuing the first + * command is significantly longer the very first time after powering + * up. Make sure the longer delay is only done the first time. + */ + if (trf->powering_up) { + delay = 20000; + trf->powering_up = false; + } else { + delay = 5000; + } + + usleep_range(delay, delay + 1000); + + ret = trf7970a_init(trf); + if (ret) + trf7970a_switch_rf_off(trf); + else + trf->state = TRF7970A_ST_IDLE; + + return ret; +} + +static int trf7970a_switch_rf(struct nfc_digital_dev *ddev, bool on) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + int ret = 0; + + dev_dbg(trf->dev, "Switching RF - state: %d, on: %d\n", trf->state, on); + + mutex_lock(&trf->lock); + + if (on) { + switch (trf->state) { + case TRF7970A_ST_OFF: + ret = trf7970a_switch_rf_on(trf); + break; + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + break; + default: + dev_err(trf->dev, "%s - Invalid request: %d %d\n", + __func__, trf->state, on); + trf7970a_switch_rf_off(trf); + } + } else { + switch (trf->state) { + case TRF7970A_ST_OFF: + break; + default: + dev_err(trf->dev, "%s - Invalid request: %d %d\n", + __func__, trf->state, on); + /* FALLTHROUGH */ + case TRF7970A_ST_IDLE: + case TRF7970A_ST_IDLE_RX_BLOCKED: + trf7970a_switch_rf_off(trf); + } + } + + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_config_rf_tech(struct trf7970a *trf, int tech) +{ + int ret = 0; + + dev_dbg(trf->dev, "rf technology: %d\n", tech); + + switch (tech) { + case NFC_DIGITAL_RF_TECH_106A: + trf->iso_ctrl = TRF7970A_ISO_CTRL_14443A_106; + break; + case NFC_DIGITAL_RF_TECH_ISO15693: + trf->iso_ctrl = TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; + break; + default: + dev_dbg(trf->dev, "Unsupported rf technology: %d\n", tech); + return -EINVAL; + } + + trf->technology = tech; + + return ret; +} + +static int trf7970a_config_framing(struct trf7970a *trf, int framing) +{ + dev_dbg(trf->dev, "framing: %d\n", framing); + + switch (framing) { + case NFC_DIGITAL_FRAMING_NFCA_SHORT: + case NFC_DIGITAL_FRAMING_NFCA_STANDARD: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT_NO_CRC; + trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N; + break; + case NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A: + case NFC_DIGITAL_FRAMING_NFCA_T4T: + case NFC_DIGITAL_FRAMING_ISO15693_INVENTORY: + case NFC_DIGITAL_FRAMING_ISO15693_T5T: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT; + trf->iso_ctrl &= ~TRF7970A_ISO_CTRL_RX_CRC_N; + break; + case NFC_DIGITAL_FRAMING_NFCA_T2T: + trf->tx_cmd = TRF7970A_CMD_TRANSMIT; + trf->iso_ctrl |= TRF7970A_ISO_CTRL_RX_CRC_N; + break; + default: + dev_dbg(trf->dev, "Unsupported Framing: %d\n", framing); + return -EINVAL; + } + + trf->framing = framing; + + return trf7970a_write(trf, TRF7970A_ISO_CTRL, trf->iso_ctrl); +} + +static int trf7970a_in_configure_hw(struct nfc_digital_dev *ddev, int type, + int param) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + int ret = 0; + + dev_dbg(trf->dev, "Configure hw - type: %d, param: %d\n", type, param); + + mutex_lock(&trf->lock); + + if (trf->state == TRF7970A_ST_OFF) { + ret = trf7970a_switch_rf_on(trf); + if (ret) + goto err_out; + } + + switch (type) { + case NFC_DIGITAL_CONFIG_RF_TECH: + ret = trf7970a_config_rf_tech(trf, param); + break; + case NFC_DIGITAL_CONFIG_FRAMING: + ret = trf7970a_config_framing(trf, param); + break; + default: + dev_dbg(trf->dev, "Unknown type: %d\n", type); + ret = -EINVAL; + } + +err_out: + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_is_iso15693_write_or_lock(u8 cmd) +{ + switch (cmd) { + case ISO15693_CMD_WRITE_SINGLE_BLOCK: + case ISO15693_CMD_LOCK_BLOCK: + case ISO15693_CMD_WRITE_MULTIPLE_BLOCK: + case ISO15693_CMD_WRITE_AFI: + case ISO15693_CMD_LOCK_AFI: + case ISO15693_CMD_WRITE_DSFID: + case ISO15693_CMD_LOCK_DSFID: + return 1; + break; + default: + return 0; + } +} + +static int trf7970a_per_cmd_config(struct trf7970a *trf, struct sk_buff *skb) +{ + u8 *req = skb->data; + u8 special_fcn_reg1, iso_ctrl; + int ret; + + trf->issue_eof = false; + + /* When issuing Type 2 read command, make sure the '4_bit_RX' bit in + * special functions register 1 is cleared; otherwise, its a write or + * sector select command and '4_bit_RX' must be set. + * + * When issuing an ISO 15693 command, inspect the flags byte to see + * what speed to use. Also, remember if the OPTION flag is set on + * a Type 5 write or lock command so the driver will know that it + * has to send an EOF in order to get a response. + */ + if ((trf->technology == NFC_DIGITAL_RF_TECH_106A) && + (trf->framing == NFC_DIGITAL_FRAMING_NFCA_T2T)) { + if (req[0] == NFC_T2T_CMD_READ) + special_fcn_reg1 = 0; + else + special_fcn_reg1 = TRF7970A_SPECIAL_FCN_REG1_4_BIT_RX; + + if (special_fcn_reg1 != trf->special_fcn_reg1) { + ret = trf7970a_write(trf, TRF7970A_SPECIAL_FCN_REG1, + special_fcn_reg1); + if (ret) + return ret; + + trf->special_fcn_reg1 = special_fcn_reg1; + } + } else if (trf->technology == NFC_DIGITAL_RF_TECH_ISO15693) { + iso_ctrl = trf->iso_ctrl & ~TRF7970A_ISO_CTRL_RFID_SPEED_MASK; + + switch (req[0] & ISO15693_REQ_FLAG_SPEED_MASK) { + case 0x00: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_662; + break; + case ISO15693_REQ_FLAG_SUB_CARRIER: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_667a; + break; + case ISO15693_REQ_FLAG_DATA_RATE: + iso_ctrl |= TRF7970A_ISO_CTRL_15693_SGL_1OF4_2648; + break; + case (ISO15693_REQ_FLAG_SUB_CARRIER | + ISO15693_REQ_FLAG_DATA_RATE): + iso_ctrl |= TRF7970A_ISO_CTRL_15693_DBL_1OF4_2669; + break; + } + + if (iso_ctrl != trf->iso_ctrl) { + ret = trf7970a_write(trf, TRF7970A_ISO_CTRL, iso_ctrl); + if (ret) + return ret; + + trf->iso_ctrl = iso_ctrl; + } + + if ((trf->framing == NFC_DIGITAL_FRAMING_ISO15693_T5T) && + trf7970a_is_iso15693_write_or_lock(req[1]) && + (req[0] & ISO15693_REQ_FLAG_OPTION)) + trf->issue_eof = true; + } + + return 0; +} + +static int trf7970a_in_send_cmd(struct nfc_digital_dev *ddev, + struct sk_buff *skb, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + char *prefix; + unsigned int len; + int ret; + + dev_dbg(trf->dev, "New request - state: %d, timeout: %d ms, len: %d\n", + trf->state, timeout, skb->len); + + if (skb->len > TRF7970A_TX_MAX) + return -EINVAL; + + mutex_lock(&trf->lock); + + if ((trf->state != TRF7970A_ST_IDLE) && + (trf->state != TRF7970A_ST_IDLE_RX_BLOCKED)) { + dev_err(trf->dev, "%s - Bogus state: %d\n", __func__, + trf->state); + ret = -EIO; + goto out_err; + } + + if (trf->aborting) { + dev_dbg(trf->dev, "Abort process complete\n"); + trf->aborting = false; + ret = -ECANCELED; + goto out_err; + } + + trf->rx_skb = nfc_alloc_recv_skb(TRF7970A_RX_SKB_ALLOC_SIZE, + GFP_KERNEL); + if (!trf->rx_skb) { + dev_dbg(trf->dev, "Can't alloc rx_skb\n"); + ret = -ENOMEM; + goto out_err; + } + + if (trf->state == TRF7970A_ST_IDLE_RX_BLOCKED) { + ret = trf7970a_cmd(trf, TRF7970A_CMD_ENABLE_RX); + if (ret) + goto out_err; + + trf->state = TRF7970A_ST_IDLE; + } + + ret = trf7970a_per_cmd_config(trf, skb); + if (ret) + goto out_err; + + trf->ddev = ddev; + trf->tx_skb = skb; + trf->cb = cb; + trf->cb_arg = arg; + trf->timeout = timeout; + trf->ignore_timeout = false; + + len = skb->len; + prefix = skb_push(skb, TRF7970A_TX_SKB_HEADROOM); + + /* TX data must be prefixed with a FIFO reset cmd, a cmd that depends + * on what the current framing is, the address of the TX length byte 1 + * register (0x1d), and the 2 byte length of the data to be transmitted. + */ + prefix[0] = TRF7970A_CMD_BIT_CTRL | + TRF7970A_CMD_BIT_OPCODE(TRF7970A_CMD_FIFO_RESET); + prefix[1] = TRF7970A_CMD_BIT_CTRL | + TRF7970A_CMD_BIT_OPCODE(trf->tx_cmd); + prefix[2] = TRF7970A_CMD_BIT_CONTINUOUS | TRF7970A_TX_LENGTH_BYTE1; + + if (trf->framing == NFC_DIGITAL_FRAMING_NFCA_SHORT) { + prefix[3] = 0x00; + prefix[4] = 0x0f; /* 7 bits */ + } else { + prefix[3] = (len & 0xf00) >> 4; + prefix[3] |= ((len & 0xf0) >> 4); + prefix[4] = ((len & 0x0f) << 4); + } + + len = min_t(int, skb->len, TRF7970A_FIFO_SIZE); + + usleep_range(1000, 2000); + + ret = trf7970a_transmit(trf, skb, len); + if (ret) { + kfree_skb(trf->rx_skb); + trf->rx_skb = NULL; + } + +out_err: + mutex_unlock(&trf->lock); + return ret; +} + +static int trf7970a_tg_configure_hw(struct nfc_digital_dev *ddev, + int type, int param) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_send_cmd(struct nfc_digital_dev *ddev, + struct sk_buff *skb, u16 timeout, + nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_listen(struct nfc_digital_dev *ddev, + u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static int trf7970a_tg_listen_mdaa(struct nfc_digital_dev *ddev, + struct digital_tg_mdaa_params *mdaa_params, + u16 timeout, nfc_digital_cmd_complete_t cb, void *arg) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Unsupported interface\n"); + + return -EINVAL; +} + +static void trf7970a_abort_cmd(struct nfc_digital_dev *ddev) +{ + struct trf7970a *trf = nfc_digital_get_drvdata(ddev); + + dev_dbg(trf->dev, "Abort process initiated\n"); + + mutex_lock(&trf->lock); + trf->aborting = true; + mutex_unlock(&trf->lock); +} + +static struct nfc_digital_ops trf7970a_nfc_ops = { + .in_configure_hw = trf7970a_in_configure_hw, + .in_send_cmd = trf7970a_in_send_cmd, + .tg_configure_hw = trf7970a_tg_configure_hw, + .tg_send_cmd = trf7970a_tg_send_cmd, + .tg_listen = trf7970a_tg_listen, + .tg_listen_mdaa = trf7970a_tg_listen_mdaa, + .switch_rf = trf7970a_switch_rf, + .abort_cmd = trf7970a_abort_cmd, +}; + +static int trf7970a_probe(struct spi_device *spi) +{ + struct device_node *np = spi->dev.of_node; + const struct spi_device_id *id = spi_get_device_id(spi); + struct trf7970a *trf; + int ret; + + if (!np) { + dev_err(&spi->dev, "No Device Tree entry\n"); + return -EINVAL; + } + + trf = devm_kzalloc(&spi->dev, sizeof(*trf), GFP_KERNEL); + if (!trf) + return -ENOMEM; + + trf->state = TRF7970A_ST_OFF; + trf->dev = &spi->dev; + trf->spi = spi; + trf->quirks = id->driver_data; + + spi->mode = SPI_MODE_1; + spi->bits_per_word = 8; + + /* There are two enable pins - both must be present */ + trf->en_gpio = of_get_named_gpio(np, "ti,enable-gpios", 0); + if (!gpio_is_valid(trf->en_gpio)) { + dev_err(trf->dev, "No EN GPIO property\n"); + return trf->en_gpio; + } + + ret = devm_gpio_request_one(trf->dev, trf->en_gpio, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN"); + if (ret) { + dev_err(trf->dev, "Can't request EN GPIO: %d\n", ret); + return ret; + } + + trf->en2_gpio = of_get_named_gpio(np, "ti,enable-gpios", 1); + if (!gpio_is_valid(trf->en2_gpio)) { + dev_err(trf->dev, "No EN2 GPIO property\n"); + return trf->en2_gpio; + } + + ret = devm_gpio_request_one(trf->dev, trf->en2_gpio, + GPIOF_DIR_OUT | GPIOF_INIT_LOW, "EN2"); + if (ret) { + dev_err(trf->dev, "Can't request EN2 GPIO: %d\n", ret); + return ret; + } + + ret = devm_request_threaded_irq(trf->dev, spi->irq, NULL, + trf7970a_irq, IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "trf7970a", trf); + if (ret) { + dev_err(trf->dev, "Can't request IRQ#%d: %d\n", spi->irq, ret); + return ret; + } + + mutex_init(&trf->lock); + INIT_DELAYED_WORK(&trf->timeout_work, trf7970a_timeout_work_handler); + + trf->regulator = devm_regulator_get(&spi->dev, "vin"); + if (IS_ERR(trf->regulator)) { + ret = PTR_ERR(trf->regulator); + dev_err(trf->dev, "Can't get VIN regulator: %d\n", ret); + goto err_destroy_lock; + } + + ret = regulator_enable(trf->regulator); + if (ret) { + dev_err(trf->dev, "Can't enable VIN: %d\n", ret); + goto err_destroy_lock; + } + + trf->powering_up = true; + + trf->ddev = nfc_digital_allocate_device(&trf7970a_nfc_ops, + TRF7970A_SUPPORTED_PROTOCOLS, + NFC_DIGITAL_DRV_CAPS_IN_CRC, TRF7970A_TX_SKB_HEADROOM, + 0); + if (!trf->ddev) { + dev_err(trf->dev, "Can't allocate NFC digital device\n"); + ret = -ENOMEM; + goto err_disable_regulator; + } + + nfc_digital_set_parent_dev(trf->ddev, trf->dev); + nfc_digital_set_drvdata(trf->ddev, trf); + spi_set_drvdata(spi, trf); + + ret = nfc_digital_register_device(trf->ddev); + if (ret) { + dev_err(trf->dev, "Can't register NFC digital device: %d\n", + ret); + goto err_free_ddev; + } + + return 0; + +err_free_ddev: + nfc_digital_free_device(trf->ddev); +err_disable_regulator: + regulator_disable(trf->regulator); +err_destroy_lock: + mutex_destroy(&trf->lock); + return ret; +} + +static int trf7970a_remove(struct spi_device *spi) +{ + struct trf7970a *trf = spi_get_drvdata(spi); + + mutex_lock(&trf->lock); + + trf7970a_switch_rf_off(trf); + trf7970a_init(trf); + + switch (trf->state) { + case TRF7970A_ST_WAIT_FOR_TX_FIFO: + case TRF7970A_ST_WAIT_FOR_RX_DATA: + case TRF7970A_ST_WAIT_FOR_RX_DATA_CONT: + case TRF7970A_ST_WAIT_TO_ISSUE_EOF: + trf7970a_send_err_upstream(trf, -ECANCELED); + break; + default: + break; + } + + mutex_unlock(&trf->lock); + + nfc_digital_unregister_device(trf->ddev); + nfc_digital_free_device(trf->ddev); + + regulator_disable(trf->regulator); + + mutex_destroy(&trf->lock); + + return 0; +} + +static const struct spi_device_id trf7970a_id_table[] = { + { "trf7970a", TRF7970A_QUIRK_IRQ_STATUS_READ_ERRATA }, + { } +}; +MODULE_DEVICE_TABLE(spi, trf7970a_id_table); + +static struct spi_driver trf7970a_spi_driver = { + .probe = trf7970a_probe, + .remove = trf7970a_remove, + .id_table = trf7970a_id_table, + .driver = { + .name = "trf7970a", + .owner = THIS_MODULE, + }, +}; + +module_spi_driver(trf7970a_spi_driver); + +MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI trf7970a RFID/NFC Transceiver Driver"); diff --git a/include/net/nfc/digital.h b/include/net/nfc/digital.h index 81af21e9bcd4..7655cfe27c34 100644 --- a/include/net/nfc/digital.h +++ b/include/net/nfc/digital.h @@ -35,6 +35,7 @@ enum { NFC_DIGITAL_RF_TECH_106A = 0, NFC_DIGITAL_RF_TECH_212F, NFC_DIGITAL_RF_TECH_424F, + NFC_DIGITAL_RF_TECH_ISO15693, NFC_DIGITAL_RF_TECH_LAST, }; @@ -50,6 +51,7 @@ enum { NFC_DIGITAL_FRAMING_NFCA_T1T, NFC_DIGITAL_FRAMING_NFCA_T2T, + NFC_DIGITAL_FRAMING_NFCA_T4T, NFC_DIGITAL_FRAMING_NFCA_NFC_DEP, NFC_DIGITAL_FRAMING_NFCF, @@ -57,6 +59,9 @@ enum { NFC_DIGITAL_FRAMING_NFCF_NFC_DEP, NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED, + NFC_DIGITAL_FRAMING_ISO15693_INVENTORY, + NFC_DIGITAL_FRAMING_ISO15693_T5T, + NFC_DIGITAL_FRAMING_LAST, }; @@ -204,6 +209,8 @@ struct nfc_digital_dev { u8 curr_rf_tech; u8 curr_nfc_dep_pni; + u16 target_fsc; + int (*skb_check_crc)(struct sk_buff *skb); void (*skb_add_crc)(struct sk_buff *skb); }; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index e80894bca1d0..2e8b40c16274 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -111,6 +111,9 @@ struct nfc_target { u8 sensf_res[NFC_SENSF_RES_MAXSIZE]; u8 hci_reader_gate; u8 logical_idx; + u8 is_iso15693; + u8 iso15693_dsfid; + u8 iso15693_uid[NFC_ISO15693_UID_MAXSIZE]; }; /** diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 6ad6cc03ccd3..9789dc95b6a8 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -150,6 +150,8 @@ enum nfc_commands { * @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED) * @NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS: Firmware download operation status * @NFC_ATTR_APDU: Secure element APDU + * @NFC_ATTR_TARGET_ISO15693_DSFID: ISO 15693 Data Storage Format Identifier + * @NFC_ATTR_TARGET_ISO15693_UID: ISO 15693 Unique Identifier */ enum nfc_attrs { NFC_ATTR_UNSPEC, @@ -178,6 +180,8 @@ enum nfc_attrs { NFC_ATTR_SE_AID, NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS, NFC_ATTR_SE_APDU, + NFC_ATTR_TARGET_ISO15693_DSFID, + NFC_ATTR_TARGET_ISO15693_UID, /* private: internal use only */ __NFC_ATTR_AFTER_LAST }; @@ -200,6 +204,7 @@ enum nfc_sdp_attr { #define NFC_SENSF_RES_MAXSIZE 18 #define NFC_GB_MAXSIZE 48 #define NFC_FIRMWARE_NAME_MAXSIZE 32 +#define NFC_ISO15693_UID_MAXSIZE 8 /* NFC protocols */ #define NFC_PROTO_JEWEL 1 @@ -208,8 +213,9 @@ enum nfc_sdp_attr { #define NFC_PROTO_ISO14443 4 #define NFC_PROTO_NFC_DEP 5 #define NFC_PROTO_ISO14443_B 6 +#define NFC_PROTO_ISO15693 7 -#define NFC_PROTO_MAX 7 +#define NFC_PROTO_MAX 8 /* NFC communication modes */ #define NFC_COMM_ACTIVE 0 @@ -227,6 +233,7 @@ enum nfc_sdp_attr { #define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) #define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) #define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B) +#define NFC_PROTO_ISO15693_MASK (1 << NFC_PROTO_ISO15693) /* NFC Secure Elements */ #define NFC_SE_UICC 0x1 diff --git a/net/nfc/core.c b/net/nfc/core.c index ca1e65f4b133..819b87702b70 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -280,9 +280,6 @@ static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) { int i; - if (dev->n_targets == 0) - return NULL; - for (i = 0; i < dev->n_targets; i++) { if (dev->targets[i].idx == target_idx) return &dev->targets[i]; @@ -546,9 +543,9 @@ error: struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx) { - struct nfc_se *se, *n; + struct nfc_se *se; - list_for_each_entry_safe(se, n, &dev->secure_elements, list) + list_for_each_entry(se, &dev->secure_elements, list) if (se->idx == se_idx) return se; @@ -655,9 +652,6 @@ int nfc_set_remote_general_bytes(struct nfc_dev *dev, u8 *gb, u8 gb_len) { pr_debug("dev_name=%s gb_len=%d\n", dev_name(&dev->dev), gb_len); - if (gb_len > NFC_MAX_GT_LEN) - return -EINVAL; - return nfc_llcp_set_remote_gb(dev, gb, gb_len); } EXPORT_SYMBOL(nfc_set_remote_general_bytes); diff --git a/net/nfc/digital.h b/net/nfc/digital.h index 08b29b55ea63..3759add68b1b 100644 --- a/net/nfc/digital.h +++ b/net/nfc/digital.h @@ -72,6 +72,12 @@ void digital_poll_next_tech(struct nfc_digital_dev *ddev); int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech); int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech); +int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech); + +int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb); +int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb); int digital_target_found(struct nfc_digital_dev *ddev, struct nfc_target *target, u8 protocol); diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c index c129d1571ca6..e01e15dbf1ab 100644 --- a/net/nfc/digital_core.c +++ b/net/nfc/digital_core.c @@ -25,6 +25,8 @@ #define DIGITAL_PROTO_NFCF_RF_TECH \ (NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK) +#define DIGITAL_PROTO_ISO15693_RF_TECH NFC_PROTO_ISO15693_MASK + struct digital_cmd { struct list_head queue; @@ -331,6 +333,18 @@ int digital_target_found(struct nfc_digital_dev *ddev, } break; + case NFC_PROTO_ISO15693: + framing = NFC_DIGITAL_FRAMING_ISO15693_T5T; + check_crc = digital_skb_check_crc_b; + add_crc = digital_skb_add_crc_b; + break; + + case NFC_PROTO_ISO14443: + framing = NFC_DIGITAL_FRAMING_NFCA_T4T; + check_crc = digital_skb_check_crc_a; + add_crc = digital_skb_add_crc_a; + break; + default: pr_err("Invalid protocol %d\n", protocol); return -EINVAL; @@ -461,7 +475,7 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A, digital_in_send_sens_req); - if (im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) { + if (matching_im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) { digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F, digital_in_send_sensf_req); @@ -469,7 +483,11 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols, digital_in_send_sensf_req); } - if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) { + if (matching_im_protocols & DIGITAL_PROTO_ISO15693_RF_TECH) + digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_ISO15693, + digital_in_send_iso15693_inv_req); + + if (matching_tm_protocols & NFC_PROTO_NFC_DEP_MASK) { if (ddev->ops->tg_listen_mdaa) { digital_add_poll_tech(ddev, 0, digital_tg_listen_mdaa); @@ -607,20 +625,30 @@ static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg, if (IS_ERR(resp)) { rc = PTR_ERR(resp); + resp = NULL; goto done; } - if (ddev->curr_protocol == NFC_PROTO_MIFARE) + if (ddev->curr_protocol == NFC_PROTO_MIFARE) { rc = digital_in_recv_mifare_res(resp); - else - rc = ddev->skb_check_crc(resp); + /* crc check is done in digital_in_recv_mifare_res() */ + goto done; + } + if (ddev->curr_protocol == NFC_PROTO_ISO14443) { + rc = digital_in_iso_dep_pull_sod(ddev, resp); + if (rc) + goto done; + } + + rc = ddev->skb_check_crc(resp); + +done: if (rc) { kfree_skb(resp); resp = NULL; } -done: data_exch->cb(data_exch->cb_context, resp, rc); kfree(data_exch); @@ -632,6 +660,7 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, { struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev); struct digital_data_exch *data_exch; + int rc; data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL); if (!data_exch) { @@ -642,13 +671,27 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target, data_exch->cb = cb; data_exch->cb_context = cb_context; - if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) - return digital_in_send_dep_req(ddev, target, skb, data_exch); + if (ddev->curr_protocol == NFC_PROTO_NFC_DEP) { + rc = digital_in_send_dep_req(ddev, target, skb, data_exch); + goto exit; + } + + if (ddev->curr_protocol == NFC_PROTO_ISO14443) { + rc = digital_in_iso_dep_push_sod(ddev, skb); + if (rc) + goto exit; + } ddev->skb_add_crc(skb); - return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete, - data_exch); + rc = digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete, + data_exch); + +exit: + if (rc) + kfree(data_exch); + + return rc; } static struct nfc_ops digital_nfc_ops = { @@ -700,6 +743,10 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops, ddev->protocols |= NFC_PROTO_FELICA_MASK; if (supported_protocols & NFC_PROTO_NFC_DEP_MASK) ddev->protocols |= NFC_PROTO_NFC_DEP_MASK; + if (supported_protocols & NFC_PROTO_ISO15693_MASK) + ddev->protocols |= NFC_PROTO_ISO15693_MASK; + if (supported_protocols & NFC_PROTO_ISO14443_MASK) + ddev->protocols |= NFC_PROTO_ISO14443_MASK; ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN; ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN; diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c index 251c8c753ebe..278c3fed27e0 100644 --- a/net/nfc/digital_technology.c +++ b/net/nfc/digital_technology.c @@ -30,6 +30,7 @@ #define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04)) #define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60)) +#define DIGITAL_SEL_RES_IS_T4T(sel_res) ((sel_res) & 0x20) #define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40) #define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00) @@ -51,6 +52,34 @@ #define DIGITAL_SENSF_REQ_RC_SC 1 #define DIGITAL_SENSF_REQ_RC_AP 2 +#define DIGITAL_CMD_ISO15693_INVENTORY_REQ 0x01 + +#define DIGITAL_ISO15693_REQ_FLAG_DATA_RATE BIT(1) +#define DIGITAL_ISO15693_REQ_FLAG_INVENTORY BIT(2) +#define DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS BIT(5) +#define DIGITAL_ISO15693_RES_FLAG_ERROR BIT(0) +#define DIGITAL_ISO15693_RES_IS_VALID(flags) \ + (!((flags) & DIGITAL_ISO15693_RES_FLAG_ERROR)) + +#define DIGITAL_ISO_DEP_I_PCB 0x02 +#define DIGITAL_ISO_DEP_PNI(pni) ((pni) & 0x01) + +#define DIGITAL_ISO_DEP_PCB_TYPE(pcb) ((pcb) & 0xC0) + +#define DIGITAL_ISO_DEP_I_BLOCK 0x00 + +#define DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb) ((pcb) & 0x08) + +static const u8 digital_ats_fsc[] = { + 16, 24, 32, 40, 48, 64, 96, 128, +}; + +#define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F) +#define DIGITAL_ATS_MAX_FSC 256 + +#define DIGITAL_RATS_BYTE1 0xE0 +#define DIGITAL_RATS_PARAM 0x80 + struct digital_sdd_res { u8 nfcid1[4]; u8 bcc; @@ -82,9 +111,127 @@ struct digital_sensf_res { u8 rd[2]; } __packed; +struct digital_iso15693_inv_req { + u8 flags; + u8 cmd; + u8 mask_len; + u64 mask; +} __packed; + +struct digital_iso15693_inv_res { + u8 flags; + u8 dsfid; + u64 uid; +} __packed; + static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev, struct nfc_target *target); +int digital_in_iso_dep_pull_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb) +{ + u8 pcb; + u8 block_type; + + if (skb->len < 1) + return -EIO; + + pcb = *skb->data; + block_type = DIGITAL_ISO_DEP_PCB_TYPE(pcb); + + /* No support fo R-block nor S-block */ + if (block_type != DIGITAL_ISO_DEP_I_BLOCK) { + pr_err("ISO_DEP R-block and S-block not supported\n"); + return -EIO; + } + + if (DIGITAL_ISO_DEP_BLOCK_HAS_DID(pcb)) { + pr_err("DID field in ISO_DEP PCB not supported\n"); + return -EIO; + } + + skb_pull(skb, 1); + + return 0; +} + +int digital_in_iso_dep_push_sod(struct nfc_digital_dev *ddev, + struct sk_buff *skb) +{ + /* + * Chaining not supported so skb->len + 1 PCB byte + 2 CRC bytes must + * not be greater than remote FSC + */ + if (skb->len + 3 > ddev->target_fsc) + return -EIO; + + skb_push(skb, 1); + + *skb->data = DIGITAL_ISO_DEP_I_PCB | ddev->curr_nfc_dep_pni; + + ddev->curr_nfc_dep_pni = + DIGITAL_ISO_DEP_PNI(ddev->curr_nfc_dep_pni + 1); + + return 0; +} + +static void digital_in_recv_ats(struct nfc_digital_dev *ddev, void *arg, + struct sk_buff *resp) +{ + struct nfc_target *target = arg; + u8 fsdi; + int rc; + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + resp = NULL; + goto exit; + } + + if (resp->len < 2) { + rc = -EIO; + goto exit; + } + + fsdi = DIGITAL_ATS_FSCI(resp->data[1]); + if (fsdi >= 8) + ddev->target_fsc = DIGITAL_ATS_MAX_FSC; + else + ddev->target_fsc = digital_ats_fsc[fsdi]; + + ddev->curr_nfc_dep_pni = 0; + + rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443); + +exit: + dev_kfree_skb(resp); + kfree(target); + + if (rc) + digital_poll_next_tech(ddev); +} + +static int digital_in_send_rats(struct nfc_digital_dev *ddev, + struct nfc_target *target) +{ + int rc; + struct sk_buff *skb; + + skb = digital_skb_alloc(ddev, 2); + if (!skb) + return -ENOMEM; + + *skb_put(skb, 1) = DIGITAL_RATS_BYTE1; + *skb_put(skb, 1) = DIGITAL_RATS_PARAM; + + rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_ats, + target); + if (rc) + kfree_skb(skb); + + return rc; +} + static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, struct sk_buff *resp) { @@ -122,8 +269,19 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, goto exit_free_skb; } + target->sel_res = sel_res; + if (DIGITAL_SEL_RES_IS_T2T(sel_res)) { nfc_proto = NFC_PROTO_MIFARE; + } else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) { + rc = digital_in_send_rats(ddev, target); + if (rc) + goto exit; + /* + * Skip target_found and don't free it for now. This will be + * done when receiving the ATS + */ + goto exit_free_skb; } else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) { nfc_proto = NFC_PROTO_NFC_DEP; } else { @@ -131,8 +289,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg, goto exit; } - target->sel_res = sel_res; - rc = digital_target_found(ddev, target, nfc_proto); exit: @@ -473,6 +629,93 @@ int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech) return rc; } +static void digital_in_recv_iso15693_inv_res(struct nfc_digital_dev *ddev, + void *arg, struct sk_buff *resp) +{ + struct digital_iso15693_inv_res *res; + struct nfc_target *target = NULL; + int rc; + + if (IS_ERR(resp)) { + rc = PTR_ERR(resp); + resp = NULL; + goto out_free_skb; + } + + if (resp->len != sizeof(*res)) { + rc = -EIO; + goto out_free_skb; + } + + res = (struct digital_iso15693_inv_res *)resp->data; + + if (!DIGITAL_ISO15693_RES_IS_VALID(res->flags)) { + PROTOCOL_ERR("ISO15693 - 10.3.1"); + rc = -EINVAL; + goto out_free_skb; + } + + target = kzalloc(sizeof(*target), GFP_KERNEL); + if (!target) { + rc = -ENOMEM; + goto out_free_skb; + } + + target->is_iso15693 = 1; + target->iso15693_dsfid = res->dsfid; + memcpy(target->iso15693_uid, &res->uid, sizeof(target->iso15693_uid)); + + rc = digital_target_found(ddev, target, NFC_PROTO_ISO15693); + + kfree(target); + +out_free_skb: + dev_kfree_skb(resp); + + if (rc) + digital_poll_next_tech(ddev); +} + +int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech) +{ + struct digital_iso15693_inv_req *req; + struct sk_buff *skb; + int rc; + + rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, + NFC_DIGITAL_RF_TECH_ISO15693); + if (rc) + return rc; + + rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, + NFC_DIGITAL_FRAMING_ISO15693_INVENTORY); + if (rc) + return rc; + + skb = digital_skb_alloc(ddev, sizeof(*req)); + if (!skb) + return -ENOMEM; + + skb_put(skb, sizeof(*req) - sizeof(req->mask)); /* No mask */ + req = (struct digital_iso15693_inv_req *)skb->data; + + /* Single sub-carrier, high data rate, no AFI, single slot + * Inventory command + */ + req->flags = DIGITAL_ISO15693_REQ_FLAG_DATA_RATE | + DIGITAL_ISO15693_REQ_FLAG_INVENTORY | + DIGITAL_ISO15693_REQ_FLAG_NB_SLOTS; + req->cmd = DIGITAL_CMD_ISO15693_INVENTORY_REQ; + req->mask_len = 0; + + rc = digital_in_send_cmd(ddev, skb, 30, + digital_in_recv_iso15693_inv_res, NULL); + if (rc) + kfree_skb(skb); + + return rc; +} + static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev) { struct sk_buff *skb; diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index a07d2b818487..1b90c0531852 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -20,14 +20,12 @@ #include "llc.h" -static struct list_head llc_engines; +static LIST_HEAD(llc_engines); int nfc_llc_init(void) { int r; - INIT_LIST_HEAD(&llc_engines); - r = nfc_llc_nop_register(); if (r) goto exit; diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 6184bd1fba3a..b486f12ae243 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -27,7 +27,7 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d}; -static struct list_head llcp_devices; +static LIST_HEAD(llcp_devices); static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb); @@ -293,9 +293,9 @@ static void nfc_llcp_sdreq_timer(unsigned long data) struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev) { - struct nfc_llcp_local *local, *n; + struct nfc_llcp_local *local; - list_for_each_entry_safe(local, n, &llcp_devices, list) + list_for_each_entry(local, &llcp_devices, list) if (local->dev == dev) return local; @@ -609,14 +609,16 @@ u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) { - struct nfc_llcp_local *local = nfc_llcp_find_local(dev); + struct nfc_llcp_local *local; + + if (gb_len < 3 || gb_len > NFC_MAX_GT_LEN) + return -EINVAL; + local = nfc_llcp_find_local(dev); if (local == NULL) { pr_err("No LLCP device\n"); return -ENODEV; } - if (gb_len < 3) - return -EINVAL; memset(local->remote_gb, 0, NFC_MAX_GT_LEN); memcpy(local->remote_gb, gb, gb_len); @@ -1622,8 +1624,6 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev) int __init nfc_llcp_init(void) { - INIT_LIST_HEAD(&llcp_devices); - return nfc_llcp_sock_init(); } diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 56db888b1cd5..6c34ac978501 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -74,7 +74,7 @@ static int __nci_request(struct nci_dev *ndev, ndev->req_status = NCI_REQ_PEND; - init_completion(&ndev->req_completion); + reinit_completion(&ndev->req_completion); req(ndev, opt); completion_rc = wait_for_completion_interruptible_timeout(&ndev->req_completion, @@ -709,6 +709,7 @@ struct nci_dev *nci_allocate_device(struct nci_ops *ops, ndev->ops = ops; ndev->tx_headroom = tx_headroom; ndev->tx_tailroom = tx_tailroom; + init_completion(&ndev->req_completion); ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops, supported_protocols, diff --git a/net/nfc/nci/spi.c b/net/nfc/nci/spi.c index f1d426f10cce..ec250e77763a 100644 --- a/net/nfc/nci/spi.c +++ b/net/nfc/nci/spi.c @@ -105,7 +105,7 @@ int nci_spi_send(struct nci_spi *nspi, if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED) goto done; - init_completion(&nspi->req_completion); + reinit_completion(&nspi->req_completion); completion_rc = wait_for_completion_interruptible_timeout( &nspi->req_completion, NCI_SPI_SEND_TIMEOUT); @@ -145,6 +145,7 @@ struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi, nspi->spi = spi; nspi->ndev = ndev; + init_completion(&nspi->req_completion); return nspi; } diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index ebbf6fb88b35..43cb1c17e267 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -94,6 +94,14 @@ static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target, target->sensf_res)) goto nla_put_failure; + if (target->is_iso15693) { + if (nla_put_u8(msg, NFC_ATTR_TARGET_ISO15693_DSFID, + target->iso15693_dsfid) || + nla_put(msg, NFC_ATTR_TARGET_ISO15693_UID, + sizeof(target->iso15693_uid), target->iso15693_uid)) + goto nla_put_failure; + } + return genlmsg_end(msg, hdr); nla_put_failure: |