NFC: Add HCI quirks to support driver (non)standard implementations

Some chips diverge from the HCI spec in their implementation of standard
features. This adds a new quirks parameter to
nfc_hci_allocate_device() to let the driver indicate its divergence.

Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index cd8fb16..ece8342 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -833,7 +833,7 @@
 		    NFC_PROTO_ISO14443_B_MASK |
 		    NFC_PROTO_NFC_DEP_MASK;
 
-	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data,
+	info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
 					     protocols, llc_name,
 					     phy_headroom + PN544_CMDS_HEADROOM,
 					     phy_tailroom, phy_payload);
diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h
index 834e364..2ff7175 100644
--- a/include/net/nfc/hci.h
+++ b/include/net/nfc/hci.h
@@ -82,6 +82,16 @@
 
 #define NFC_HCI_MAX_GATES		256
 
+/*
+ * These values can be specified by a driver to indicate it requires some
+ * adaptation of the HCI standard.
+ *
+ * NFC_HCI_QUIRK_SHORT_CLEAR - send HCI_ADM_CLEAR_ALL_PIPE cmd with no params
+ */
+enum {
+	NFC_HCI_QUIRK_SHORT_CLEAR	= 0,
+};
+
 struct nfc_hci_dev {
 	struct nfc_dev *ndev;
 
@@ -131,11 +141,14 @@
 
 	u8 *gb;
 	size_t gb_len;
+
+	unsigned long quirks;
 };
 
 /* hci device allocation */
 struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 					    struct nfc_hci_init_data *init_data,
+					    unsigned long quirks,
 					    u32 protocols,
 					    const char *llc_name,
 					    int tx_headroom,
diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c
index 7d99410..64f922b 100644
--- a/net/nfc/hci/command.c
+++ b/net/nfc/hci/command.c
@@ -280,14 +280,19 @@
 static int nfc_hci_clear_all_pipes(struct nfc_hci_dev *hdev)
 {
 	u8 param[2];
+	size_t param_len = 2;
 
 	/* TODO: Find out what the identity reference data is
 	 * and fill param with it. HCI spec 6.1.3.5 */
 
 	pr_debug("\n");
 
+	if (test_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &hdev->quirks))
+		param_len = 0;
+
 	return nfc_hci_execute_cmd(hdev, NFC_HCI_ADMIN_PIPE,
-				   NFC_HCI_ADM_CLEAR_ALL_PIPE, param, 2, NULL);
+				   NFC_HCI_ADM_CLEAR_ALL_PIPE, param, param_len,
+				   NULL);
 }
 
 int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate)
diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c
index d9190da..755a6b9 100644
--- a/net/nfc/hci/core.c
+++ b/net/nfc/hci/core.c
@@ -795,6 +795,7 @@
 
 struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
 					    struct nfc_hci_init_data *init_data,
+					    unsigned long quirks,
 					    u32 protocols,
 					    const char *llc_name,
 					    int tx_headroom,
@@ -838,6 +839,8 @@
 
 	memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
 
+	hdev->quirks = quirks;
+
 	return hdev;
 }
 EXPORT_SYMBOL(nfc_hci_allocate_device);