OpenWrt NFC support

The purpose of this document is to describe the steps / process required to correctly build and test Linux NFC (neard) on MT7620 based WRTnode + TRF7970A EVA board connected platform, using the Openwrt SDK, toolchain and associated MT7620 specific drivers in conjunction with the neard NFC stack.


1.Scope

This document describes how to build the necessary components for NFC using the Openwrt Trunk. It also covers the adding of a Linux-based NFC driver to Openwrt Trunk Linux 3.18.7, the building of the neard stack, installing or placing onto a target file system, and installing the associated tools (Python, libnl, Dbus) that are needed to test NFC functions on that target file system and associated hardware.

Link to Openwrt Buidroot: http://wiki.openwrt.org/doc/howto/buildroot.exigence

Linux NFC tools (neard):https://01.org/zh/linux-nfc/documentation/howtos

The building of the kernel, the associated driver modules, neard, and Python tools is done on a host machine (Linux PC) and the resulting output(firmware) is flashed to the WRTnode board .


2. Hardware

WRTnode(MT7620):http://wrtnode.com/

WRTnode-shield (1)

TRF7970A Evaluation Module :http://www.ti.com/tool/trf7970aevm

 

Picture1

 

This module is originally for the NFC/RFID test that using PC. It has a serial-to-USB chip that convert the data from the board to PC, and it comes with a Windows application to read and wire the tags with different protocols like ISO15693, ISO14443, etc.

To detach it from the control of MSP430 MCU, we need to cut the DATA_CLK line and remove the jumpers between HDR_6 and HDR5, connect HDR_5 to HDR_4

The following pins in the TRF7970 board should connect to WRTnode:

  • SIMO
  • SOMI
  • SLAVE SELECT
  • DATA_CLK
  • EN
  • GND
  • IRQ

 

 

The following figure is the Windows GUI interface of the TRF7970 application

 

111


 

 

3. SPI Driver

 

In the WRTnode PCB board, the Chip Select 1 is configured as the reference clock. Hence if the second SPI connect to the board, we must release the SPI CS1 pin to the spi driver.121

We can see the initial value for the SPI_REFCLK0_MODE is 0x1, which means that this pin is shared with the reference clock .

 

The multiplex of the pins is centrally controlled by driver “pinmux” in drivers/pinctrl/pinctrl-rt2880.c

The according modification in Device Tree:

		spi_pins: spi {
			spi {
				ralink,group = "spi";
				ralink,function = "spi";
			};
			cs1 {
				ralink,group = "spi refclk";
				ralink,function = "spi refclk";
 			};

Besides that, there is a bug in the drivers/spi/spi-rt2880.c,the original SPI driver thinks that it just have 1 Chip Select pin :

 

static struct rt2880_spi_ops spi_ops[] = {
	{
		.init_hw = rt2880_spi_reset,
		.num_cs = 1,
	}, {
		.init_hw = rt5350_spi_reset,
		.num_cs = 2,
	},
};
static const struct of_device_id rt2880_spi_match[] = {
	{ .compatible = "ralink,rt2880-spi", .data = &spi_ops[0]},
	{ .compatible = "ralink,rt5350-spi", .data = &spi_ops[1]},
	{},
};

The driver treat rt2880 and rt5350 differently even though the MT7620 using rt2880 has two Chip Select pins.

Thus we need to modify the device tree to “ralink,rt5350-spi” and solder the SPI CS1 a pull up resistor.

Final device tree link:https://github.com/relayr/openwrt-experiments/blob/master/dts/WRTNODE.dts

 

It is also important to notice that the TRF7970A only works in CPOL=0 CPHA =1

1211

In  drivers/spi/spi-rt2880.c

rt2880_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) is responsible for setting up the correct clock polarity.

1212

It is critical to make the second SPI device work with correct clock polarity, the codes about the SPI mode is given as following:

        reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG(cs));
	reg = (reg & ~SPICFG_MSBFIRST);
	if (!(spi->mode & SPI_LSB_FIRST))
		reg |= SPICFG_MSBFIRST;
	reg = (reg & ~(SPICFG_SPICLKPOL | SPICFG_RXCLKEDGE_FALLING |SPICFG_TXCLKEDGE_FALLING));
	
	switch(spi->mode & (SPI_CPOL | SPI_CPHA)) {
		case SPI_MODE_0:
			reg |= SPICFG_SPICLKPOL | SPICFG_TXCLKEDGE_FALLING;
			break;
		case SPI_MODE_1:
			reg |= SPICFG_RXCLKEDGE_FALLING;
			break;
		case SPI_MODE_2:
			reg |= SPICFG_RXCLKEDGE_FALLING;
			break;
		case SPI_MODE_3:
			reg |= SPICFG_TXCLKEDGE_FALLING;
			break;
	}
	rt2880_spi_write(rs, RAMIPS_SPI_CFG(cs), reg);

 

4. TRF7970A Linux Driver

 

The device tree register for the TRF7970A should follow the documentation in the Linux kernel: http://lxr.linux.no/linux+v3.18.7/Documentation/devicetree/bindings/net/nfc/trf7970a.txt

TRF7970A

* 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.
– autosuspend-delay: Specify autosuspend delay in milliseconds.
– vin-voltage-override: Specify voltage of VIN pin in microvolts.
– irq-status-read-quirk: Specify that the trf7970a being used has the
“IRQ Status Read” erratum.
– en2-rf-quirk: Specify that the trf7970a being used has the “EN2 RF”
erratum.

The original properties in the device tree have to be modified in the Openwrt based MT7620 platforms:

 

			nfc@1 {
				#address-cells = ;
				#size-cells = ;
				compatible = "ti,trf7970a";
				reg = ;
				spi-max-frequency = ;
				interrupt-parent = <&gpio0>;
				interrupts = ;
				ti,enable-gpios = <&gpio0 21 1>,
						  <&gpio0 20 1>,
						  <&gpio0 19 1>;
				vin-supply = <&mmciv>;
				vin-voltage-override = ;
				autosuspend-delay = ;
				irq-status-read-quirk;
				en2-rf-quirk;
				status = "okay";
			};

Since we are using GPIO#19 as the input for the hardware IRQ detection, we should also set up the number of GPIO after the “ti,enable-gpios EN EN2”.

The reason why we need to setup the GPIO in addition to specify  the interrupt parent is due to the bug in the ralink GPIO driver, which needs to set the GPIO direction IN before requrire IRQ

I need to send the ticket to Openwrt and submit a patch for this.

Vin properties should link to the gpio regulator in the device tree.

according modification in trf7970A driver: /trunk/build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/linux-ramips_mt7620/linux-3.18.7/drivers/nfc/trf7970a.c

 

--- trf7970a-origin.c	2015-04-02 12:21:21.745871000 +0200
+++ trf7970a.c	2015-04-08 22:17:21.077806097 +0200
@@ -11,7 +11,7 @@
  * it under the terms of the GNU General Public License version 2  of
  * the License as published by the Free Software Foundation.
  */
-
+#define DEBUG 1
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/netdevice.h>
@@ -409,7 +409,7 @@
 		(ISO15693_REQ_FLAG_SUB_CARRIER | ISO15693_REQ_FLAG_DATA_RATE)
 
 enum trf7970a_state {
-	TRF7970A_ST_PWR_OFF,
+	TRF7970A_ST_PWR_OFF = 1,
 	TRF7970A_ST_RF_OFF,
 	TRF7970A_ST_IDLE,
 	TRF7970A_ST_IDLE_RX_BLOCKED,
@@ -448,6 +448,7 @@
 	bool				issue_eof;
 	int				en2_gpio;
 	int				en_gpio;
+	int				irq;
 	struct mutex			lock;
 	unsigned int			timeout;
 	bool				ignore_timeout;
@@ -2025,9 +2026,22 @@
 	if (of_property_read_bool(np, "en2-rf-quirk"))
 		trf->quirks |= TRF7970A_QUIRK_EN2_MUST_STAY_LOW;
 
+	trf->irq = of_get_named_gpio(np, "ti,enable-gpios", 2);
+	if (!gpio_is_valid(trf->irq)) {
+		dev_err(trf->dev, "No IRQ property\n");
+		return trf->irq;
+	}
+
+	ret = devm_gpio_request_one(trf->dev, trf->irq,
+			GPIOF_DIR_IN, "trf7970a irq");
+	if (ret) {
+		dev_err(trf->dev, "Can't request IRQ GPIO: %d\n", ret);
+		return ret;
+	}
+

5. Kernel Compilation

To support the registration in the Device Tree, we should compile the correct driver in the kernel.

Since there is no GUI configuration options in the make kernel_menuconfig, we should modify /trunk/target/linux/ramips/mt7620/config-3.18:

The following CONFIGs should be added in this file.

CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
CONFIG_REGULATOR_GPIO=y
CONFIG_NFC=y 
CONFIG_NFC_DIGITAL=y
CONFIG_NFC_NCI=y
CONFIG_NFC_NCI_SPI=y
CONFIG_NFC_HCI=y
CONFIG_NFC_SHDLC=y
CONFIG_NFC_LLCP=y
CONFIG_NFC_TRF7970A=y
CONFIG_NFC_PN533=n
CONFIG_NFC_SIM=n
CONFIG_NFC_PORT100=n
CONFIG_NFC_PN544=n
CONFIG_NFC_MICROREAD=n
CONFIG_NFC_MRVL=n
CONFIG_NFC_ST21NFCA=n
CONFIG_NFC_ST21NFCB=n
CONFIG_NFC_WILINK=y
CONFIG_PM=y
CONFIG_PM_RUNTIME=y
CONFIG_PM_DEBUG=n

GPIO regulator driver is to support the mmciv in device tree, and NFC, PM are necessary to the TRF7970a.


 

6. Linux-NFC tools(neard) cross compile

 

11111

 

Linux-nfc is a opensource stack tool to support TRF7970A. However, its website just has the HOWTOs of the PC platfom.

Our MT7620 platform is ramips structure, and thus we need cross compile the tool to the ramips platform, which need the Openwrt SDK.:http://wiki.openwrt.org/doc/devel/crosscompile

Download the SDK here: https://downloads.openwrt.org/snapshots/trunk/ramips/mt7620/

Git clone the neard: git clone https://github.com/sheenhx/neard.git

In the Host PC you should apt-get install the necessary libraries in HOWTOs.:https://01.org/linux-nfc/documentation/howtos

Export the PATH to the Openwrt SDK and modify the bootstrap-configure in neard folder:

 

export TOOLCHAIN=/opt/cross/mipsel/7620/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2  
export PATH="$TOOLCHAIN/bin:$PATH"
export PATH="/home/sheen/trunk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin:$PATH"
STAGING_DIR=/home/sheen/trunk/staging_dir/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2
export STAGING_DIR
 
    ./configure --enable-maintainer-mode \
	--enable-debug \
        --disable-systemd \
        --prefix=/home/sheen/nfc/usr \
        --exec-prefix=/home/sheen/nfc/usr\
        --sysconfdir=/home/sheen/nfc/etc \
        --host=mipsel-openwrt-linux-uclibc \
        MANIFEST_TOOL=: \
        CC=mipsel-openwrt-linux-uclibc-gcc-4.8.3 \
        LD=mipsel-openwrt-linux-uclibc-ld \
        RANLIB=mipsel-openwrt-uclibc-ranlib \
        LDFLAGS=-L/home/sheen/trunk/OpenWrt-SDK-ramips-mt7620_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/lib

 

And follow the other instructions in HOWTOs, copy the files in prefix folder and copy the test folder to the target Openwrt system.


 

7. Testing NFC/RFID Tag Functionality Using neard

In the Openwrt platform, the following packages should be installed before test the TRF7970A:

  • libnl
  • glib2
  • dbus
  • dbus-python

To interact (read or write) with NFC tag platforms from the target file system, place or present an NFC tag platform to the antenna on the TRF7970A board.

Go to the location on the target file system where the neard files reside and start neard

 

In the neard directory on the target file system, the following commands are to be done in the order listed.
Each time a tag is presented, step 2 must precede the list or dump commands. Otherwise, the transmitter will not be on to power the passive tag.
1. test/test-adapter powered nfc0 on
2. test/test-adapter poll nfc0 on Initiator
3. test/test-tag list
4. test/test-tag dump

 

Test the tag using the write command and read the tag with dump command

 

root@OpenWrt:~# /test/test-tag list
[ /org/neard/nfc0/tag6 ]
Protocol = ISO-15693
ReadOnly = false
Type = Type 5
Adapter = /org/neard/nfc0
root@OpenWrt:~# /test/test-tag write /org/neard/nfc0/tag6 Text UTF-8 en-US hello,relayr!
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record0 ]
Representation = hello,relayr
Type = Text
Language = en-US
Encoding = UTF-8
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record0 ]
Representation = hello,relayr
Type = Text
Language = en-US
Encoding = UTF-8
root@OpenWrt:~# /test/test-tag write /org/neard/nfc0/tag6 Text UTF-8 en-US hello,relayr!sdfasdf
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record1 ]
Representation = hello,relay
Type = Text
Language = en-US
Encoding = UTF-8
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record1 ]
Representation = hello,relay
Type = Text
Language = en-US
Encoding = UTF-8
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record1 ]
Representation = hello,relay
Type = Text
Language = en-US
Encoding = UTF-8
root@OpenWrt:~# /test/test-tag write /org/neard/nfc0/tag6 Text UTF-8 en-US hello,relay3
root@OpenWrt:~# /test/test-tag dump
[ /org/neard/nfc0/tag6 ]
[ /org/neard/nfc0/tag6/record2 ]
Representation = hello,relay3
Type = Text
Language = en-US
Encoding = UTF-8

 

Okay, have fun!

Recent Posts

Recent Comments

Archives

Categories

Meta

sheenhx Written by:

One Comment

  1. November 2, 2015
    Reply

    Hi, this is a comment.
    To delete a comment, just log in and view the post's comments. There you will have the option to edit or delete them.

Leave a Reply

Your email address will not be published. Required fields are marked *