]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
NFC: mei: Add a common mei bus API for NFC drivers
authorEric Lapuyade <eric.lapuyade@linux.intel.com>
Mon, 15 Apr 2013 09:19:20 +0000 (11:19 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Mon, 15 Apr 2013 22:39:31 +0000 (00:39 +0200)
This isolates the common code that is required to use an mei bus nfc
device from an NFC HCI drivers. This prepares for future drivers for
NFC chips connected behind an Intel Management Engine controller.
The microread_mei HCI driver is also modified to use that common code.

Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/mei_phy.c [new file with mode: 0644]
drivers/nfc/mei_phy.h [new file with mode: 0644]
drivers/nfc/microread/Kconfig
drivers/nfc/microread/mei.c

index e57034971cccacaafb3814bef8dd5d0aa8b7e68d..4775d4e61b881de43d93f1643b462e47e6cc52a4 100644 (file)
@@ -26,6 +26,16 @@ config NFC_WILINK
          Say Y here to compile support for Texas Instrument's NFC WiLink driver
          into the kernel or say M to compile it as module.
 
+config NFC_MEI_PHY
+       tristate "MEI bus NFC device support"
+       depends on INTEL_MEI_BUS_NFC && NFC_HCI
+       help
+         This adds support to use an mei bus nfc device. Select this if you
+         will use an HCI NFC driver for an NFC chip connected behind an
+         Intel's Management Engine chip.
+
+         If unsure, say N.
+
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/microread/Kconfig"
 
index a189ada0926ab94eb93def94c83abd9890478b39..aa6bd657ef409cca9ebe158737df2fdce11a85f8 100644 (file)
@@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544)         += pn544/
 obj-$(CONFIG_NFC_MICROREAD)    += microread/
 obj-$(CONFIG_NFC_PN533)                += pn533.o
 obj-$(CONFIG_NFC_WILINK)       += nfcwilink.o
+obj-$(CONFIG_NFC_MEI_PHY)      += mei_phy.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
new file mode 100644 (file)
index 0000000..b8f8abc
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * MEI Library for mei bus nfc device access
+ *
+ * Copyright (C) 2013  Intel Corporation. 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, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/nfc.h>
+
+#include "mei_phy.h"
+
+struct mei_nfc_hdr {
+       u8 cmd;
+       u8 status;
+       u16 req_id;
+       u32 reserved;
+       u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+#define MEI_DUMP_SKB_IN(info, skb)                             \
+do {                                                           \
+       pr_debug("%s:\n", info);                                \
+       print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET,   \
+                       16, 1, (skb)->data, (skb)->len, false); \
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb)                            \
+do {                                                           \
+       pr_debug("%s:\n", info);                                \
+       print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET,   \
+                      16, 1, (skb)->data, (skb)->len, false);  \
+} while (0)
+
+int nfc_mei_phy_enable(void *phy_id)
+{
+       int r;
+       struct nfc_mei_phy *phy = phy_id;
+
+       pr_info("%s\n", __func__);
+
+       if (phy->powered == 1)
+               return 0;
+
+       r = mei_cl_enable_device(phy->device);
+       if (r < 0) {
+                pr_err("MEI_PHY: Could not enable device\n");
+                return r;
+       }
+
+       phy->powered = 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
+
+void nfc_mei_phy_disable(void *phy_id)
+{
+       struct nfc_mei_phy *phy = phy_id;
+
+       pr_info("%s\n", __func__);
+
+       mei_cl_disable_device(phy->device);
+
+       phy->powered = 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
+{
+       struct nfc_mei_phy *phy = phy_id;
+       int r;
+
+       MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+       r = mei_cl_send(phy->device, skb->data, skb->len);
+       if (r > 0)
+               r = 0;
+
+       return r;
+}
+
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
+{
+       struct nfc_mei_phy *phy = context;
+
+       if (phy->hard_fault != 0)
+               return;
+
+       if (events & BIT(MEI_CL_EVENT_RX)) {
+               struct sk_buff *skb;
+               int reply_size;
+
+               skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+               if (!skb)
+                       return;
+
+               reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
+               if (reply_size < MEI_NFC_HEADER_SIZE) {
+                       kfree(skb);
+                       return;
+               }
+
+               skb_put(skb, reply_size);
+               skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+               MEI_DUMP_SKB_IN("mei frame read", skb);
+
+               nfc_hci_recv_frame(phy->hdev, skb);
+       }
+}
+EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
+
+struct nfc_phy_ops mei_phy_ops = {
+       .write = nfc_mei_phy_write,
+       .enable = nfc_mei_phy_enable,
+       .disable = nfc_mei_phy_disable,
+};
+EXPORT_SYMBOL_GPL(mei_phy_ops);
+
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
+{
+       struct nfc_mei_phy *phy;
+
+       phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
+       if (!phy)
+               return NULL;
+
+       phy->device = device;
+       mei_cl_set_drvdata(device, phy);
+
+       return phy;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
+
+void nfc_mei_phy_free(struct nfc_mei_phy *phy)
+{
+       kfree(phy);
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("mei bus NFC device interface");
diff --git a/drivers/nfc/mei_phy.h b/drivers/nfc/mei_phy.h
new file mode 100644 (file)
index 0000000..d669900
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef __LOCAL_MEI_PHY_H_
+#define __LOCAL_MEI_PHY_H_
+
+#include <linux/mei_cl_bus.h>
+#include <net/nfc/hci.h>
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+
+struct nfc_mei_phy {
+       struct mei_cl_device *device;
+       struct nfc_hci_dev *hdev;
+
+       int powered;
+
+       int hard_fault;         /*
+                                * < 0 if hardware error occured
+                                * and prevents normal operation.
+                                */
+};
+
+extern struct nfc_phy_ops mei_phy_ops;
+
+int nfc_mei_phy_enable(void *phy_id);
+void nfc_mei_phy_disable(void *phy_id);
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
+void nfc_mei_phy_free(struct nfc_mei_phy *phy);
+
+#endif /* __LOCAL_MEI_PHY_H_ */
index 572305be6e371bbafdde60e030bea1875084ee60..951d5542f6bc749fea4977d58d19ffd8df2791ba 100644 (file)
@@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C
 
 config NFC_MICROREAD_MEI
        tristate "NFC Microread MEI support"
-       depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+       depends on NFC_MICROREAD && NFC_MEI_PHY
        ---help---
          This module adds support for the mei interface of adapters using
          Inside microread chipsets.  Select this if your microread chipset
index ca33ae193935bc3c3e75ffa809aa0573a5e24692..1ad044dce7b60acfa686d72d842670d64bd02efb 100644 (file)
  */
 
 #include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mei_cl_bus.h>
-
+#include <linux/mod_devicetable.h>
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
 #include <net/nfc/llc.h>
 
+#include "../mei_phy.h"
 #include "microread.h"
 
 #define MICROREAD_DRIVER_NAME "microread"
 
-struct mei_nfc_hdr {
-       u8 cmd;
-       u8 status;
-       u16 req_id;
-       u32 reserved;
-       u16 data_size;
-} __attribute__((packed));
-
-#define MEI_NFC_HEADER_SIZE 10
-#define MEI_NFC_MAX_HCI_PAYLOAD 300
-#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
-
-struct microread_mei_phy {
-       struct mei_cl_device *device;
-       struct nfc_hci_dev *hdev;
-
-       int powered;
-
-       int hard_fault;         /*
-                                * < 0 if hardware error occured (e.g. i2c err)
-                                * and prevents normal operation.
-                                */
-};
-
-#define MEI_DUMP_SKB_IN(info, skb)                                     \
-do {                                                           \
-       pr_debug("%s:\n", info);                                \
-       print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET,     \
-                      16, 1, (skb)->data, (skb)->len, 0);      \
-} while (0)
-
-#define MEI_DUMP_SKB_OUT(info, skb)                                    \
-do {                                                           \
-       pr_debug("%s:\n", info);                                \
-       print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET,     \
-                      16, 1, (skb)->data, (skb)->len, 0);      \
-} while (0)
-
-static int microread_mei_enable(void *phy_id)
-{
-       struct microread_mei_phy *phy = phy_id;
-
-       pr_info(DRIVER_DESC ": %s\n", __func__);
-
-       phy->powered = 1;
-
-       return 0;
-}
-
-static void microread_mei_disable(void *phy_id)
-{
-       struct microread_mei_phy *phy = phy_id;
-
-       pr_info(DRIVER_DESC ": %s\n", __func__);
-
-       phy->powered = 0;
-}
-
-/*
- * Writing a frame must not return the number of written bytes.
- * It must return either zero for success, or <0 for error.
- * In addition, it must not alter the skb
- */
-static int microread_mei_write(void *phy_id, struct sk_buff *skb)
-{
-       struct microread_mei_phy *phy = phy_id;
-       int r;
-
-       MEI_DUMP_SKB_OUT("mei frame sent", skb);
-
-       r = mei_cl_send(phy->device, skb->data, skb->len);
-       if (r > 0)
-               r = 0;
-
-       return r;
-}
-
-static void microread_event_cb(struct mei_cl_device *device, u32 events,
-                              void *context)
-{
-       struct microread_mei_phy *phy = context;
-
-       if (phy->hard_fault != 0)
-               return;
-
-       if (events & BIT(MEI_CL_EVENT_RX)) {
-               struct sk_buff *skb;
-               int reply_size;
-
-               skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
-               if (!skb)
-                       return;
-
-               reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
-               if (reply_size < MEI_NFC_HEADER_SIZE) {
-                       kfree(skb);
-                       return;
-               }
-
-               skb_put(skb, reply_size);
-               skb_pull(skb, MEI_NFC_HEADER_SIZE);
-
-               MEI_DUMP_SKB_IN("mei frame read", skb);
-
-               nfc_hci_recv_frame(phy->hdev, skb);
-       }
-}
-
-static struct nfc_phy_ops mei_phy_ops = {
-       .write = microread_mei_write,
-       .enable = microread_mei_enable,
-       .disable = microread_mei_disable,
-};
-
 static int microread_mei_probe(struct mei_cl_device *device,
                               const struct mei_cl_device_id *id)
 {
-       struct microread_mei_phy *phy;
+       struct nfc_mei_phy *phy;
        int r;
 
        pr_info("Probing NFC microread\n");
 
-       phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+       phy = nfc_mei_phy_alloc(device);
        if (!phy) {
                pr_err("Cannot allocate memory for microread mei phy.\n");
                return -ENOMEM;
        }
 
-       phy->device = device;
-       mei_cl_set_drvdata(device, phy);
-
-       r = mei_cl_register_event_cb(device, microread_event_cb, phy);
+       r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
        if (r) {
                pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
                goto err_out;
@@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device,
        return 0;
 
 err_out:
-       kfree(phy);
+       nfc_mei_phy_free(phy);
 
        return r;
 }
 
 static int microread_mei_remove(struct mei_cl_device *device)
 {
-       struct microread_mei_phy *phy = mei_cl_get_drvdata(device);
+       struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
 
        pr_info("Removing microread\n");
 
        microread_remove(phy->hdev);
 
-       if (phy->powered)
-               microread_mei_disable(phy);
+       nfc_mei_phy_disable(phy);
 
-       kfree(phy);
+       nfc_mei_phy_free(phy);
 
        return 0;
 }