Explorar o código

Merge tag 'nfc-next-4.5-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next

Samuel Ortiz says:

====================
NFC 4.5 pull request

This is the first NFC pull request for 4.5 and it brings:

- A new driver for the STMicroelectronics ST95HF NFC chipset.
  The ST95HF is an NFC digital transceiver with an embedded analog
  front-end and as such relies on the Linux NFC digital
  implementation. This is the 3rd user of the NFC digital stack.

- ACPI support for the ST st-nci and st21nfca drivers.

- A small improvement for the nfcsim driver, as we can now tune
  the Rx delay through sysfs.

- A bunch of minor cleanups and small fixes from Christophe Ricard,
  for a few drivers and the NFC core code.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
David S. Miller %!s(int64=9) %!d(string=hai) anos
pai
achega
15ab90f400

+ 50 - 0
Documentation/devicetree/bindings/net/nfc/st95hf.txt

@@ -0,0 +1,50 @@
+* STMicroelectronics : NFC Transceiver ST95HF
+
+ST NFC Transceiver is required to attach with SPI bus.
+ST95HF node should be defined in DT as SPI slave device of SPI
+master with which ST95HF transceiver is physically connected.
+The properties defined below are required to be the part of DT
+to include ST95HF transceiver into the platform.
+
+Required properties:
+===================
+- reg: Address of SPI slave "ST95HF transceiver" on SPI master bus.
+
+- compatible: should be "st,st95hf" for ST95HF NFC transceiver
+
+- spi-max-frequency: Max. operating SPI frequency for ST95HF
+	transceiver.
+
+- enable-gpio: GPIO line to enable ST95HF transceiver.
+
+- interrupt-parent : Standard way to specify the controller to which
+	ST95HF transceiver's interrupt is routed.
+
+- interrupts : Standard way to define ST95HF transceiver's out
+	interrupt.
+
+Optional property:
+=================
+- st95hfvin-supply : This is an optional property. It contains a
+	phandle to ST95HF transceiver's regulator supply node in DT.
+
+Example:
+=======
+spi@9840000 {
+	reg = <0x9840000 0x110>;
+	#address-cells = <1>;
+	#size-cells = <0>;
+	cs-gpios = <&pio0 4>;
+	status = "okay";
+
+	st95hf@0{
+		reg = <0>;
+		compatible = "st,st95hf";
+		status = "okay";
+		spi-max-frequency = <1000000>;
+		enable-gpio = <&pio4 0>;
+		interrupt-parent = <&pio0>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+	};
+
+};

+ 5 - 0
MAINTAINERS

@@ -7523,7 +7523,12 @@ F:	net/nfc/
 F:	include/net/nfc/
 F:	include/uapi/linux/nfc.h
 F:	drivers/nfc/
+F:	include/linux/platform_data/microread.h
+F:	include/linux/platform_data/nfcmrvl.h
+F:	include/linux/platform_data/nxp-nci.h
 F:	include/linux/platform_data/pn544.h
+F:	include/linux/platform_data/st21nfca.h
+F:	include/linux/platform_data/st-nci.h
 F:	Documentation/devicetree/bindings/net/nfc/
 
 NFS, SUNRPC, AND LOCKD CLIENTS

+ 1 - 0
drivers/nfc/Kconfig

@@ -76,4 +76,5 @@ source "drivers/nfc/st21nfca/Kconfig"
 source "drivers/nfc/st-nci/Kconfig"
 source "drivers/nfc/nxp-nci/Kconfig"
 source "drivers/nfc/s3fwrn5/Kconfig"
+source "drivers/nfc/st95hf/Kconfig"
 endmenu

+ 1 - 0
drivers/nfc/Makefile

@@ -16,3 +16,4 @@ obj-$(CONFIG_NFC_ST21NFCA)  	+= st21nfca/
 obj-$(CONFIG_NFC_ST_NCI)	+= st-nci/
 obj-$(CONFIG_NFC_NXP_NCI)	+= nxp-nci/
 obj-$(CONFIG_NFC_S3FWRN5)	+= s3fwrn5/
+obj-$(CONFIG_NFC_ST95HF)	+= st95hf/

+ 6 - 6
drivers/nfc/fdp/i2c.c

@@ -298,6 +298,12 @@ static int fdp_nci_i2c_probe(struct i2c_client *client,
 		return -ENODEV;
 	}
 
+	/* Checking if we have an irq */
+	if (client->irq <= 0) {
+		nfc_err(dev, "IRQ not present\n");
+		return -ENODEV;
+	}
+
 	phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy),
 			   GFP_KERNEL);
 	if (!phy)
@@ -307,12 +313,6 @@ static int fdp_nci_i2c_probe(struct i2c_client *client,
 	phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
 	i2c_set_clientdata(client, phy);
 
-	/* Checking if we have an irq */
-	if (client->irq <= 0) {
-		dev_err(dev, "IRQ not present\n");
-		return -ENODEV;
-	}
-
 	r = request_threaded_irq(client->irq, NULL, fdp_nci_i2c_irq_thread_fn,
 				 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
 				 FDP_I2C_DRIVER_NAME, phy);

+ 0 - 2
drivers/nfc/microread/i2c.c

@@ -50,8 +50,6 @@ struct microread_i2c_phy {
 	struct i2c_client *i2c_dev;
 	struct nfc_hci_dev *hdev;
 
-	int irq;
-
 	int hard_fault;		/*
 				 * < 0 if hardware error occured (e.g. i2c err)
 				 * and prevents normal operation.

+ 7 - 3
drivers/nfc/nfcsim.c

@@ -32,6 +32,8 @@
 #define NFCSIM_POLL_TARGET	2
 #define NFCSIM_POLL_DUAL	(NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
 
+#define RX_DEFAULT_DELAY	5
+
 struct nfcsim {
 	struct nfc_dev *nfc_dev;
 
@@ -51,6 +53,8 @@ struct nfcsim {
 
 	u8 initiator;
 
+	u32 rx_delay;
+
 	data_exchange_cb_t cb;
 	void *cb_context;
 
@@ -320,10 +324,9 @@ static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
 	 * If packet transmission occurs immediately between them, we have a
 	 * non-stop flow of several tens of thousands SYMM packets per second
 	 * and a burning cpu.
-	 *
-	 * TODO: Add support for a sysfs entry to control this delay.
 	 */
-	queue_delayed_work(wq, &peer->recv_work, msecs_to_jiffies(5));
+	queue_delayed_work(wq, &peer->recv_work,
+			msecs_to_jiffies(dev->rx_delay));
 
 	mutex_unlock(&peer->lock);
 
@@ -461,6 +464,7 @@ static struct nfcsim *nfcsim_init_dev(void)
 	if (rc)
 		goto free_nfc_dev;
 
+	dev->rx_delay = RX_DEFAULT_DELAY;
 	return dev;
 
 free_nfc_dev:

+ 3 - 31
drivers/nfc/nxp-nci/i2c.c

@@ -52,7 +52,6 @@ struct nxp_nci_i2c_phy {
 
 	unsigned int gpio_en;
 	unsigned int gpio_fw;
-	unsigned int gpio_irq;
 
 	int hard_fault; /*
 			 * < 0 if hardware error occurred (e.g. i2c err)
@@ -85,7 +84,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
 		return phy->hard_fault;
 
 	r = i2c_master_send(client, skb->data, skb->len);
-	if (r == -EREMOTEIO) {
+	if (r < 0) {
 		/* Retry, chip was in standby */
 		usleep_range(110000, 120000);
 		r = i2c_master_send(client, skb->data, skb->len);
@@ -264,8 +263,6 @@ exit_irq_none:
 	return IRQ_NONE;
 }
 
-#ifdef CONFIG_OF
-
 static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
 {
 	struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
@@ -294,48 +291,24 @@ static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
 	}
 	phy->gpio_fw = r;
 
-	r = irq_of_parse_and_map(pp, 0);
-	if (r < 0) {
-		nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
-		return r;
-	}
-	client->irq = r;
-
 	return 0;
 }
 
-#else
-
-static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
-{
-	return -ENODEV;
-}
-
-#endif
-
 static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy)
 {
 	struct i2c_client *client = phy->i2c_dev;
-	struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq;
+	struct gpio_desc *gpiod_en, *gpiod_fw;
 
 	gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2, GPIOD_OUT_LOW);
 	gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1, GPIOD_OUT_LOW);
-	gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN);
 
-	if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) {
+	if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw)) {
 		nfc_err(&client->dev, "No GPIOs\n");
 		return -EINVAL;
 	}
 
-	client->irq = gpiod_to_irq(gpiod_irq);
-	if (client->irq < 0) {
-		nfc_err(&client->dev, "No IRQ\n");
-		return -EINVAL;
-	}
-
 	phy->gpio_en = desc_to_gpio(gpiod_en);
 	phy->gpio_fw = desc_to_gpio(gpiod_fw);
-	phy->gpio_irq = desc_to_gpio(gpiod_irq);
 
 	return 0;
 }
@@ -374,7 +347,6 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
 	} else if (pdata) {
 		phy->gpio_en = pdata->gpio_en;
 		phy->gpio_fw = pdata->gpio_fw;
-		client->irq = pdata->irq;
 	} else if (ACPI_HANDLE(&client->dev)) {
 		r = nxp_nci_i2c_acpi_config(phy);
 		if (r < 0)

+ 1 - 45
drivers/nfc/pn544/i2c.c

@@ -166,7 +166,6 @@ struct pn544_i2c_phy {
 	struct nfc_hci_dev *hdev;
 
 	unsigned int gpio_en;
-	unsigned int gpio_irq;
 	unsigned int gpio_fw;
 	unsigned int en_polarity;
 
@@ -879,9 +878,8 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
 {
 	struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
 	const struct acpi_device_id *id;
-	struct gpio_desc *gpiod_en, *gpiod_irq, *gpiod_fw;
+	struct gpio_desc *gpiod_en, *gpiod_fw;
 	struct device *dev;
-	int ret;
 
 	if (!client)
 		return -EINVAL;
@@ -914,32 +912,9 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
 
 	phy->gpio_fw = desc_to_gpio(gpiod_fw);
 
-	/* Get IRQ GPIO */
-	gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0,
-					 GPIOD_IN);
-	if (IS_ERR(gpiod_irq)) {
-		nfc_err(dev, "Unable to get IRQ GPIO\n");
-		return -ENODEV;
-	}
-
-	phy->gpio_irq = desc_to_gpio(gpiod_irq);
-
-	/* Map the pin to an IRQ */
-	ret = gpiod_to_irq(gpiod_irq);
-	if (ret < 0) {
-		nfc_err(dev, "Fail pin IRQ mapping\n");
-		return ret;
-	}
-
-	nfc_info(dev, "GPIO resource, no:%d irq:%d\n",
-		 desc_to_gpio(gpiod_irq), ret);
-	client->irq = ret;
-
 	return 0;
 }
 
-#ifdef CONFIG_OF
-
 static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
 {
 	struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
@@ -996,15 +971,6 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
 		goto err_gpio_fw;
 	}
 
-	/* IRQ */
-	ret = irq_of_parse_and_map(pp, 0);
-	if (ret < 0) {
-		nfc_err(&client->dev,
-			"Unable to get irq, error: %d\n", ret);
-		goto err_gpio_fw;
-	}
-	client->irq = ret;
-
 	return 0;
 
 err_gpio_fw:
@@ -1015,15 +981,6 @@ err_dt:
 	return ret;
 }
 
-#else
-
-static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
-{
-	return -ENODEV;
-}
-
-#endif
-
 static int pn544_hci_i2c_probe(struct i2c_client *client,
 			       const struct i2c_device_id *id)
 {
@@ -1076,7 +1033,6 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
 
 		phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
 		phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
-		phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
 	/* Using ACPI */
 	} else if (ACPI_HANDLE(&client->dev)) {
 		r = pn544_hci_i2c_acpi_request_resources(client);

+ 1 - 1
drivers/nfc/s3fwrn5/core.c

@@ -147,7 +147,7 @@ static struct nci_ops s3fwrn5_nci_ops = {
 };
 
 int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
-	struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload)
+	const struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload)
 {
 	struct s3fwrn5_info *info;
 	int ret;

+ 1 - 1
drivers/nfc/s3fwrn5/i2c.c

@@ -125,7 +125,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
 	return 0;
 }
 
-static struct s3fwrn5_phy_ops i2c_phy_ops = {
+static const struct s3fwrn5_phy_ops i2c_phy_ops = {
 	.set_wake = s3fwrn5_i2c_set_wake,
 	.set_mode = s3fwrn5_i2c_set_mode,
 	.get_mode = s3fwrn5_i2c_get_mode,

+ 2 - 2
drivers/nfc/s3fwrn5/s3fwrn5.h

@@ -44,7 +44,7 @@ struct s3fwrn5_info {
 	void *phy_id;
 	struct device *pdev;
 
-	struct s3fwrn5_phy_ops *phy_ops;
+	const struct s3fwrn5_phy_ops *phy_ops;
 	unsigned int max_payload;
 
 	struct s3fwrn5_fw_info fw_info;
@@ -90,7 +90,7 @@ static inline int s3fwrn5_write(struct s3fwrn5_info *info, struct sk_buff *skb)
 }
 
 int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
-	struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload);
+	const struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload);
 void s3fwrn5_remove(struct nci_dev *ndev);
 
 int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,

+ 7 - 11
drivers/nfc/st-nci/Kconfig

@@ -1,19 +1,14 @@
 config NFC_ST_NCI
-	tristate "STMicroelectronics ST NCI NFC driver"
-	depends on NFC_NCI
-	default n
+	tristate
 	---help---
 	  STMicroelectronics NFC NCI chips core driver. It implements the chipset
 	  NCI logic and hooks into the NFC kernel APIs. Physical layers will
 	  register against it.
 
-	  To compile this driver as a module, choose m here. The module will
-	  be called st-nci.
-	  Say N if unsure.
-
 config NFC_ST_NCI_I2C
-	tristate "NFC ST NCI i2c support"
-	depends on NFC_ST_NCI && I2C
+	tristate "STMicroelectronics ST NCI NFC driver (I2C)"
+	depends on NFC_NCI && I2C
+	select NFC_ST_NCI
 	---help---
 	  This module adds support for an I2C interface to the
 	  STMicroelectronics NFC NCI chips familly.
@@ -23,8 +18,9 @@ config NFC_ST_NCI_I2C
 	  Say N if unsure.
 
 config NFC_ST_NCI_SPI
-	tristate "NFC ST NCI spi support"
-	depends on NFC_ST_NCI && SPI
+	tristate "STMicroelectronics ST NCI NFC driver (SPI)"
+	depends on NFC_NCI && SPI
+	select NFC_ST_NCI
 	---help---
 	  This module adds support for an SPI interface to the
 	  STMicroelectronics NFC NCI chips familly.

+ 63 - 17
drivers/nfc/st-nci/i2c.c

@@ -20,8 +20,10 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
+#include <linux/acpi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/nfc.h>
@@ -40,11 +42,7 @@
 
 #define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c"
 
-static struct i2c_device_id st_nci_i2c_id_table[] = {
-	{ST_NCI_DRIVER_NAME, 0},
-	{}
-};
-MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
+#define ST_NCI_GPIO_NAME_RESET "clf_reset"
 
 struct st_nci_i2c_phy {
 	struct i2c_client *i2c_dev;
@@ -210,7 +208,43 @@ static struct nfc_phy_ops i2c_phy_ops = {
 	.disable = st_nci_i2c_disable,
 };
 
-#ifdef CONFIG_OF
+static int st_nci_i2c_acpi_request_resources(struct i2c_client *client)
+{
+	struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
+	const struct acpi_device_id *id;
+	struct gpio_desc *gpiod_reset;
+	struct device *dev;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* Match the struct device against a given list of ACPI IDs */
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	/* Get RESET GPIO from ACPI */
+	gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
+					   GPIOD_OUT_HIGH);
+	if (IS_ERR(gpiod_reset)) {
+		nfc_err(dev, "Unable to get RESET GPIO\n");
+		return -ENODEV;
+	}
+
+	phy->gpio_reset = desc_to_gpio(gpiod_reset);
+
+	phy->irq_polarity = irq_get_trigger_type(client->irq);
+
+	phy->se_status.is_ese_present =
+				device_property_present(dev, "ese-present");
+	phy->se_status.is_uicc_present =
+				device_property_present(dev, "uicc-present");
+
+	return 0;
+}
+
 static int st_nci_i2c_of_request_resources(struct i2c_client *client)
 {
 	struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
@@ -232,7 +266,7 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
 
 	/* GPIO request and configuration */
 	r = devm_gpio_request_one(&client->dev, gpio,
-				GPIOF_OUT_INIT_HIGH, "clf_reset");
+				GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET);
 	if (r) {
 		nfc_err(&client->dev, "Failed to request reset pin\n");
 		return r;
@@ -248,12 +282,6 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
 
 	return 0;
 }
-#else
-static int st_nci_i2c_of_request_resources(struct i2c_client *client)
-{
-	return -ENODEV;
-}
-#endif
 
 static int st_nci_i2c_request_resources(struct i2c_client *client)
 {
@@ -272,7 +300,8 @@ static int st_nci_i2c_request_resources(struct i2c_client *client)
 	phy->irq_polarity = pdata->irq_polarity;
 
 	r = devm_gpio_request_one(&client->dev,
-			phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
+			phy->gpio_reset, GPIOF_OUT_INIT_HIGH,
+			ST_NCI_GPIO_NAME_RESET);
 	if (r) {
 		pr_err("%s : reset gpio_request failed\n", __FILE__);
 		return r;
@@ -322,6 +351,12 @@ static int st_nci_i2c_probe(struct i2c_client *client,
 				"Cannot get platform resources\n");
 			return r;
 		}
+	} else if (ACPI_HANDLE(&client->dev)) {
+		r = st_nci_i2c_acpi_request_resources(client);
+		if (r) {
+			nfc_err(&client->dev, "Cannot get ACPI data\n");
+			return r;
+		}
 	} else {
 		nfc_err(&client->dev,
 			"st_nci platform resources not available\n");
@@ -358,7 +393,19 @@ static int st_nci_i2c_remove(struct i2c_client *client)
 	return 0;
 }
 
-#ifdef CONFIG_OF
+static struct i2c_device_id st_nci_i2c_id_table[] = {
+	{ST_NCI_DRIVER_NAME, 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
+
+static const struct acpi_device_id st_nci_i2c_acpi_match[] = {
+	{"SMO2101"},
+	{"SMO2102"},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, st_nci_i2c_acpi_match);
+
 static const struct of_device_id of_st_nci_i2c_match[] = {
 	{ .compatible = "st,st21nfcb-i2c", },
 	{ .compatible = "st,st21nfcb_i2c", },
@@ -366,19 +413,18 @@ static const struct of_device_id of_st_nci_i2c_match[] = {
 	{}
 };
 MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
-#endif
 
 static struct i2c_driver st_nci_i2c_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = ST_NCI_I2C_DRIVER_NAME,
 		.of_match_table = of_match_ptr(of_st_nci_i2c_match),
+		.acpi_match_table = ACPI_PTR(st_nci_i2c_acpi_match),
 	},
 	.probe = st_nci_i2c_probe,
 	.id_table = st_nci_i2c_id_table,
 	.remove = st_nci_i2c_remove,
 };
-
 module_i2c_driver(st_nci_i2c_driver);
 
 MODULE_LICENSE("GPL");

+ 0 - 1
drivers/nfc/st-nci/ndlc.c

@@ -20,7 +20,6 @@
 #include <net/nfc/nci_core.h>
 
 #include "st-nci.h"
-#include "ndlc.h"
 
 #define NDLC_TIMER_T1		100
 #define NDLC_TIMER_T1_WAIT	400

+ 1 - 2
drivers/nfc/st-nci/se.c

@@ -331,7 +331,7 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
 
 	switch (event) {
 	case ST_NCI_EVT_CONNECTIVITY:
-
+		r = nfc_se_connectivity(ndev->nfc_dev, host);
 	break;
 	case ST_NCI_EVT_TRANSACTION:
 		/* According to specification etsi 102 622
@@ -392,7 +392,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
 }
 EXPORT_SYMBOL_GPL(st_nci_hci_event_received);
 
-
 void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
 			       struct sk_buff *skb)
 {

+ 63 - 18
drivers/nfc/st-nci/spi.c

@@ -20,8 +20,10 @@
 #include <linux/module.h>
 #include <linux/spi/spi.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
+#include <linux/acpi.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/nfc.h>
@@ -34,18 +36,14 @@
 
 /* ndlc header */
 #define ST_NCI_FRAME_HEADROOM	1
-#define ST_NCI_FRAME_TAILROOM 0
+#define ST_NCI_FRAME_TAILROOM	0
 
 #define ST_NCI_SPI_MIN_SIZE 4   /* PCB(1) + NCI Packet header(3) */
 #define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */
 
 #define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
 
-static struct spi_device_id st_nci_spi_id_table[] = {
-	{ST_NCI_SPI_DRIVER_NAME, 0},
-	{}
-};
-MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
+#define ST_NCI_GPIO_NAME_RESET "clf_reset"
 
 struct st_nci_spi_phy {
 	struct spi_device *spi_dev;
@@ -225,7 +223,43 @@ static struct nfc_phy_ops spi_phy_ops = {
 	.disable = st_nci_spi_disable,
 };
 
-#ifdef CONFIG_OF
+static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev)
+{
+	struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev);
+	const struct acpi_device_id *id;
+	struct gpio_desc *gpiod_reset;
+	struct device *dev;
+
+	if (!spi_dev)
+		return -EINVAL;
+
+	dev = &spi_dev->dev;
+
+	/* Match the struct device against a given list of ACPI IDs */
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	/* Get RESET GPIO from ACPI */
+	gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
+					   GPIOD_OUT_HIGH);
+	if (IS_ERR(gpiod_reset)) {
+		nfc_err(dev, "Unable to get RESET GPIO\n");
+		return -ENODEV;
+	}
+
+	phy->gpio_reset = desc_to_gpio(gpiod_reset);
+
+	phy->irq_polarity = irq_get_trigger_type(spi_dev->irq);
+
+	phy->se_status.is_ese_present =
+				device_property_present(dev, "ese-present");
+	phy->se_status.is_uicc_present =
+				device_property_present(dev, "uicc-present");
+
+	return 0;
+}
+
 static int st_nci_spi_of_request_resources(struct spi_device *dev)
 {
 	struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
@@ -247,7 +281,7 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
 
 	/* GPIO request and configuration */
 	r = devm_gpio_request_one(&dev->dev, gpio,
-				GPIOF_OUT_INIT_HIGH, "clf_reset");
+				GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET);
 	if (r) {
 		nfc_err(&dev->dev, "Failed to request reset pin\n");
 		return r;
@@ -263,12 +297,6 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
 
 	return 0;
 }
-#else
-static int st_nci_spi_of_request_resources(struct spi_device *dev)
-{
-	return -ENODEV;
-}
-#endif
 
 static int st_nci_spi_request_resources(struct spi_device *dev)
 {
@@ -287,7 +315,8 @@ static int st_nci_spi_request_resources(struct spi_device *dev)
 	phy->irq_polarity = pdata->irq_polarity;
 
 	r = devm_gpio_request_one(&dev->dev,
-			phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
+			phy->gpio_reset, GPIOF_OUT_INIT_HIGH,
+			ST_NCI_GPIO_NAME_RESET);
 	if (r) {
 		pr_err("%s : reset gpio_request failed\n", __FILE__);
 		return r;
@@ -338,6 +367,12 @@ static int st_nci_spi_probe(struct spi_device *dev)
 				"Cannot get platform resources\n");
 			return r;
 		}
+	} else if (ACPI_HANDLE(&dev->dev)) {
+		r = st_nci_spi_acpi_request_resources(dev);
+		if (r) {
+			nfc_err(&dev->dev, "Cannot get ACPI data\n");
+			return r;
+		}
 	} else {
 		nfc_err(&dev->dev,
 			"st_nci platform resources not available\n");
@@ -374,24 +409,34 @@ static int st_nci_spi_remove(struct spi_device *dev)
 	return 0;
 }
 
-#ifdef CONFIG_OF
+static struct spi_device_id st_nci_spi_id_table[] = {
+	{ST_NCI_SPI_DRIVER_NAME, 0},
+	{}
+};
+MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
+
+static const struct acpi_device_id st_nci_spi_acpi_match[] = {
+	{"SMO2101", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, st_nci_spi_acpi_match);
+
 static const struct of_device_id of_st_nci_spi_match[] = {
 	{ .compatible = "st,st21nfcb-spi", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
-#endif
 
 static struct spi_driver st_nci_spi_driver = {
 	.driver = {
 		.name = ST_NCI_SPI_DRIVER_NAME,
 		.of_match_table = of_match_ptr(of_st_nci_spi_match),
+		.acpi_match_table = ACPI_PTR(st_nci_spi_acpi_match),
 	},
 	.probe = st_nci_spi_probe,
 	.id_table = st_nci_spi_id_table,
 	.remove = st_nci_spi_remove,
 };
-
 module_spi_driver(st_nci_spi_driver);
 
 MODULE_LICENSE("GPL");

+ 4 - 9
drivers/nfc/st21nfca/Kconfig

@@ -1,20 +1,15 @@
 config NFC_ST21NFCA
-	tristate "STMicroelectronics ST21NFCA NFC driver"
-	depends on NFC_HCI
+	tristate
 	select CRC_CCITT
-	default n
 	---help---
 	  STMicroelectronics ST21NFCA core driver. It implements the chipset
 	  HCI logic and hooks into the NFC kernel APIs. Physical layers will
 	  register against it.
 
-	  To compile this driver as a module, choose m here. The module will
-	  be called st21nfca.
-	  Say N if unsure.
-
 config NFC_ST21NFCA_I2C
-	tristate "NFC ST21NFCA i2c support"
-	depends on NFC_ST21NFCA && I2C && NFC_SHDLC
+	tristate "STMicroelectronics ST21NFCA NFC driver (I2C)"
+	depends on NFC_HCI && I2C && NFC_SHDLC
+	select NFC_ST21NFCA
 	---help---
 	  This module adds support for the STMicroelectronics st21nfca i2c interface.
 	  Select this if your platform is using the i2c bus.

+ 60 - 20
drivers/nfc/st21nfca/i2c.c

@@ -21,8 +21,10 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/of_irq.h>
 #include <linux/of_gpio.h>
+#include <linux/acpi.h>
 #include <linux/miscdevice.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -60,12 +62,7 @@
 
 #define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c"
 
-static struct i2c_device_id st21nfca_hci_i2c_id_table[] = {
-	{ST21NFCA_HCI_DRIVER_NAME, 0},
-	{}
-};
-
-MODULE_DEVICE_TABLE(i2c, st21nfca_hci_i2c_id_table);
+#define ST21NFCA_GPIO_NAME_EN "clf_enable"
 
 struct st21nfca_i2c_phy {
 	struct i2c_client *i2c_dev;
@@ -167,7 +164,6 @@ static void st21nfca_hci_i2c_disable(void *phy_id)
 {
 	struct st21nfca_i2c_phy *phy = phy_id;
 
-	pr_info("\n");
 	gpio_set_value(phy->gpio_ena, 0);
 
 	phy->powered = 0;
@@ -210,7 +206,6 @@ static int st21nfca_hci_i2c_write(void *phy_id, struct sk_buff *skb)
 
 	I2C_DUMP_SKB("st21nfca_hci_i2c_write", skb);
 
-
 	if (phy->hard_fault != 0)
 		return phy->hard_fault;
 
@@ -509,7 +504,41 @@ static struct nfc_phy_ops i2c_phy_ops = {
 	.disable = st21nfca_hci_i2c_disable,
 };
 
-#ifdef CONFIG_OF
+static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client)
+{
+	struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
+	const struct acpi_device_id *id;
+	struct gpio_desc *gpiod_ena;
+	struct device *dev;
+
+	if (!client)
+		return -EINVAL;
+
+	dev = &client->dev;
+
+	/* Match the struct device against a given list of ACPI IDs */
+	id = acpi_match_device(dev->driver->acpi_match_table, dev);
+	if (!id)
+		return -ENODEV;
+
+	/* Get EN GPIO from ACPI */
+	gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1,
+					 GPIOD_OUT_LOW);
+	if (!IS_ERR(gpiod_ena))
+		phy->gpio_ena = desc_to_gpio(gpiod_ena);
+
+	phy->gpio_ena = desc_to_gpio(gpiod_ena);
+
+	phy->irq_polarity = irq_get_trigger_type(client->irq);
+
+	phy->se_status.is_ese_present =
+				device_property_present(dev, "ese-present");
+	phy->se_status.is_uicc_present =
+				device_property_present(dev, "uicc-present");
+
+	return 0;
+}
+
 static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
 {
 	struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
@@ -530,7 +559,7 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
 
 	/* GPIO request and configuration */
 	r = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH,
-				  "clf_enable");
+				  ST21NFCA_GPIO_NAME_EN);
 	if (r) {
 		nfc_err(&client->dev, "Failed to request enable pin\n");
 		return r;
@@ -547,12 +576,6 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
 
 	return 0;
 }
-#else
-static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
-{
-	return -ENODEV;
-}
-#endif
 
 static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
 {
@@ -572,7 +595,8 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
 
 	if (phy->gpio_ena > 0) {
 		r = devm_gpio_request_one(&client->dev, phy->gpio_ena,
-					  GPIOF_OUT_INIT_HIGH, "clf_enable");
+					  GPIOF_OUT_INIT_HIGH,
+					  ST21NFCA_GPIO_NAME_EN);
 		if (r) {
 			pr_err("%s : ena gpio_request failed\n", __FILE__);
 			return r;
@@ -628,6 +652,12 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
 			nfc_err(&client->dev, "Cannot get platform resources\n");
 			return r;
 		}
+	} else if (ACPI_HANDLE(&client->dev)) {
+		r = st21nfca_hci_i2c_acpi_request_resources(client);
+		if (r) {
+			nfc_err(&client->dev, "Cannot get ACPI data\n");
+			return r;
+		}
 	} else {
 		nfc_err(&client->dev, "st21nfca platform resources not available\n");
 		return -ENODEV;
@@ -670,26 +700,36 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
 	return 0;
 }
 
-#ifdef CONFIG_OF
+static struct i2c_device_id st21nfca_hci_i2c_id_table[] = {
+	{ST21NFCA_HCI_DRIVER_NAME, 0},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, st21nfca_hci_i2c_id_table);
+
+static const struct acpi_device_id st21nfca_hci_i2c_acpi_match[] = {
+	{"SMO2100", 0},
+	{}
+};
+MODULE_DEVICE_TABLE(acpi, st21nfca_hci_i2c_acpi_match);
+
 static const struct of_device_id of_st21nfca_i2c_match[] = {
 	{ .compatible = "st,st21nfca-i2c", },
 	{ .compatible = "st,st21nfca_i2c", },
 	{}
 };
 MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match);
-#endif
 
 static struct i2c_driver st21nfca_hci_i2c_driver = {
 	.driver = {
 		.owner = THIS_MODULE,
 		.name = ST21NFCA_HCI_I2C_DRIVER_NAME,
 		.of_match_table = of_match_ptr(of_st21nfca_i2c_match),
+		.acpi_match_table = ACPI_PTR(st21nfca_hci_i2c_acpi_match),
 	},
 	.probe = st21nfca_hci_i2c_probe,
 	.id_table = st21nfca_hci_i2c_id_table,
 	.remove = st21nfca_hci_i2c_remove,
 };
-
 module_i2c_driver(st21nfca_hci_i2c_driver);
 
 MODULE_LICENSE("GPL");

+ 3 - 2
drivers/nfc/st21nfca/se.c

@@ -312,7 +312,8 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
 
 	switch (event) {
 	case ST21NFCA_EVT_CONNECTIVITY:
-		break;
+		r = nfc_se_connectivity(hdev->ndev, host);
+	break;
 	case ST21NFCA_EVT_TRANSACTION:
 		/*
 		 * According to specification etsi 102 622
@@ -342,7 +343,7 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
 		       transaction->aid_len + 4, transaction->params_len);
 
 		r = nfc_se_transaction(hdev->ndev, host, transaction);
-		break;
+	break;
 	default:
 		nfc_err(&hdev->ndev->dev, "Unexpected event on connectivity gate\n");
 		return 1;

+ 10 - 0
drivers/nfc/st95hf/Kconfig

@@ -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 - 0
drivers/nfc/st95hf/Makefile

@@ -0,0 +1,6 @@
+#
+# Makefile for STMicroelectronics NFC transceiver ST95HF
+#
+
+obj-$(CONFIG_NFC_ST95HF)	+= st95hf.o
+st95hf-objs			:= spi.o core.o

+ 1273 - 0
drivers/nfc/st95hf/core.c

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

+ 167 - 0
drivers/nfc/st95hf/spi.c

@@ -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 - 0
drivers/nfc/st95hf/spi.h

@@ -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

+ 4 - 4
drivers/nfc/trf7970a.c

@@ -2139,7 +2139,7 @@ static int trf7970a_remove(struct spi_device *spi)
 #ifdef CONFIG_PM_SLEEP
 static int trf7970a_suspend(struct device *dev)
 {
-	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct spi_device *spi = to_spi_device(dev);
 	struct trf7970a *trf = spi_get_drvdata(spi);
 
 	dev_dbg(dev, "Suspend\n");
@@ -2155,7 +2155,7 @@ static int trf7970a_suspend(struct device *dev)
 
 static int trf7970a_resume(struct device *dev)
 {
-	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct spi_device *spi = to_spi_device(dev);
 	struct trf7970a *trf = spi_get_drvdata(spi);
 	int ret;
 
@@ -2174,7 +2174,7 @@ static int trf7970a_resume(struct device *dev)
 #ifdef CONFIG_PM
 static int trf7970a_pm_runtime_suspend(struct device *dev)
 {
-	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct spi_device *spi = to_spi_device(dev);
 	struct trf7970a *trf = spi_get_drvdata(spi);
 	int ret;
 
@@ -2191,7 +2191,7 @@ static int trf7970a_pm_runtime_suspend(struct device *dev)
 
 static int trf7970a_pm_runtime_resume(struct device *dev)
 {
-	struct spi_device *spi = container_of(dev, struct spi_device, dev);
+	struct spi_device *spi = to_spi_device(dev);
 	struct trf7970a *trf = spi_get_drvdata(spi);
 	int ret;
 

+ 1 - 1
include/linux/platform_data/microread.h

@@ -1,5 +1,5 @@
 /*
- * Driver include for the PN544 NFC chip.
+ * Driver include for the Inside Secure microread NFC Chip.
  *
  * Copyright (C) 2011 Tieto Poland
  * Copyright (C) 2012 Intel Corporation. All rights reserved.

+ 1 - 0
include/net/nfc/nfc.h

@@ -299,6 +299,7 @@ void nfc_driver_failure(struct nfc_dev *dev, int err);
 
 int nfc_se_transaction(struct nfc_dev *dev, u8 se_idx,
 		       struct nfc_evt_transaction *evt_transaction);
+int nfc_se_connectivity(struct nfc_dev *dev, u8 se_idx);
 int nfc_add_se(struct nfc_dev *dev, u32 se_idx, u16 type);
 int nfc_remove_se(struct nfc_dev *dev, u32 se_idx);
 struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx);

+ 13 - 0
net/nfc/core.c

@@ -953,6 +953,19 @@ out:
 }
 EXPORT_SYMBOL(nfc_se_transaction);
 
+int nfc_se_connectivity(struct nfc_dev *dev, u8 se_idx)
+{
+	int rc;
+
+	pr_debug("connectivity: %x\n", se_idx);
+
+	device_lock(&dev->dev);
+	rc = nfc_genl_se_connectivity(dev, se_idx);
+	device_unlock(&dev->dev);
+	return rc;
+}
+EXPORT_SYMBOL(nfc_se_connectivity);
+
 static void nfc_release(struct device *d)
 {
 	struct nfc_dev *dev = to_nfc_dev(d);

+ 2 - 1
net/nfc/digital_core.c

@@ -20,7 +20,8 @@
 #include "digital.h"
 
 #define DIGITAL_PROTO_NFCA_RF_TECH \
-	(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | NFC_PROTO_NFC_DEP_MASK)
+	(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | \
+	NFC_PROTO_NFC_DEP_MASK | NFC_PROTO_ISO14443_MASK)
 
 #define DIGITAL_PROTO_NFCB_RF_TECH	NFC_PROTO_ISO14443_B_MASK
 

+ 3 - 3
net/nfc/nci/core.c

@@ -610,14 +610,14 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
 	struct nci_core_conn_create_cmd *cmd;
 	struct core_conn_create_data data;
 
+	if (!number_destination_params)
+		return -EINVAL;
+
 	data.length = params_len + sizeof(struct nci_core_conn_create_cmd);
 	cmd = kzalloc(data.length, GFP_KERNEL);
 	if (!cmd)
 		return -ENOMEM;
 
-	if (!number_destination_params)
-		return -EINVAL;
-
 	cmd->destination_type = destination_type;
 	cmd->number_destination_params = number_destination_params;
 	memcpy(cmd->params, params, params_len);

+ 1 - 1
net/nfc/nci/hci.c

@@ -676,7 +676,7 @@ int nci_hci_connect_gate(struct nci_dev *ndev,
 	break;
 	default:
 		pipe = nci_hci_create_pipe(ndev, dest_host, dest_gate, &r);
-		if (pipe < 0)
+		if (pipe == NCI_HCI_INVALID_PIPE)
 			return r;
 		pipe_created = true;
 		break;

+ 37 - 0
net/nfc/netlink.c

@@ -552,6 +552,43 @@ free_msg:
 	return -EMSGSIZE;
 }
 
+int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx)
+{
+	struct nfc_se *se;
+	struct sk_buff *msg;
+	void *hdr;
+
+	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+			  NFC_EVENT_SE_CONNECTIVITY);
+	if (!hdr)
+		goto free_msg;
+
+	se = nfc_find_se(dev, se_idx);
+	if (!se)
+		goto free_msg;
+
+	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
+	    nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
+	    nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
+		goto nla_put_failure;
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
 static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
 				u32 portid, u32 seq,
 				struct netlink_callback *cb,

+ 1 - 0
net/nfc/nfc.h

@@ -105,6 +105,7 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type);
 int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx);
 int nfc_genl_se_transaction(struct nfc_dev *dev, u8 se_idx,
 			    struct nfc_evt_transaction *evt_transaction);
+int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx);
 
 struct nfc_dev *nfc_get_device(unsigned int idx);