NFC: Sony Port-100 Series driver
authorThierry Escande <thierry.escande@linux.intel.com>
Fri, 4 Oct 2013 10:12:00 +0000 (12:12 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Mon, 7 Oct 2013 12:09:33 +0000 (14:09 +0200)
This adds support for the Sony NFC USB dongle RC-S380, based on the
Port-100 chip. This dongle is an analog frontend and does not implement
the digital layer. This driver uses the nfc_digital module which is an
implementation of the NFC Digital Protocol stack.

This patch is a skeleton. It only registers the dongle against the NFC
digital protocol stack. All NFC digital operation functions are stubbed
out.

Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com>
Cc: Stephen Tiedemann <stephen.tiedemann@gmail.com>
Tested-by: Cho, Yu-Chen <acho@suse.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/port100.c [new file with mode: 0644]

index b0b64cc..c1fb206 100644 (file)
@@ -46,6 +46,16 @@ config NFC_SIM
 
          If unsure, say N.
 
+config NFC_PORT100
+       tristate "Sony NFC Port-100 Series USB device support"
+       depends on USB
+       depends on NFC_DIGITAL
+       help
+         This adds support for Sony Port-100 chip based USB devices such as the
+         RC-S380 dongle.
+
+         If unsure, say N.
+
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/microread/Kconfig"
 
index be7636a..c715fe8 100644 (file)
@@ -8,5 +8,6 @@ obj-$(CONFIG_NFC_PN533)         += pn533.o
 obj-$(CONFIG_NFC_WILINK)       += nfcwilink.o
 obj-$(CONFIG_NFC_MEI_PHY)      += mei_phy.o
 obj-$(CONFIG_NFC_SIM)          += nfcsim.o
+obj-$(CONFIG_NFC_PORT100)      += port100.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/port100.c b/drivers/nfc/port100.c
new file mode 100644 (file)
index 0000000..f167907
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Sony NFC Port-100 Series driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Partly based/Inspired by Stephen Tiedemann's nfcpy
+ *
+ * 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 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <net/nfc/digital.h>
+
+#define VERSION "0.1"
+
+#define SONY_VENDOR_ID    0x054c
+#define RCS380_PRODUCT_ID 0x06c1
+
+#define PORT100_PROTOCOLS (NFC_PROTO_JEWEL_MASK    | \
+                          NFC_PROTO_MIFARE_MASK   | \
+                          NFC_PROTO_FELICA_MASK   | \
+                          NFC_PROTO_NFC_DEP_MASK)
+
+#define PORT100_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
+                             NFC_DIGITAL_DRV_CAPS_TG_CRC)
+
+struct port100 {
+       struct nfc_digital_dev *nfc_digital_dev;
+
+       int skb_headroom;
+       int skb_tailroom;
+
+       struct usb_device *udev;
+       struct usb_interface *interface;
+};
+
+static void port100_abort_cmd(struct nfc_digital_dev *ddev)
+{
+}
+
+static int port100_switch_rf(struct nfc_digital_dev *ddev, bool on)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_in_configure_hw(struct nfc_digital_dev *ddev, int type,
+                                  int param)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_in_send_cmd(struct nfc_digital_dev *ddev,
+                              struct sk_buff *skb, u16 _timeout,
+                              nfc_digital_cmd_complete_t cb, void *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_tg_configure_hw(struct nfc_digital_dev *ddev, int type,
+                                  int param)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_tg_send_cmd(struct nfc_digital_dev *ddev,
+                              struct sk_buff *skb, u16 timeout,
+                              nfc_digital_cmd_complete_t cb, void *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_listen_mdaa(struct nfc_digital_dev *ddev,
+                              struct digital_tg_mdaa_params *params,
+                              u16 timeout,
+                              nfc_digital_cmd_complete_t cb, void *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static int port100_listen(struct nfc_digital_dev *ddev, u16 timeout,
+                         nfc_digital_cmd_complete_t cb, void *arg)
+{
+       return -EOPNOTSUPP;
+}
+
+static struct nfc_digital_ops port100_digital_ops = {
+       .in_configure_hw = port100_in_configure_hw,
+       .in_send_cmd = port100_in_send_cmd,
+
+       .tg_listen_mdaa = port100_listen_mdaa,
+       .tg_listen = port100_listen,
+       .tg_configure_hw = port100_tg_configure_hw,
+       .tg_send_cmd = port100_tg_send_cmd,
+
+       .switch_rf = port100_switch_rf,
+       .abort_cmd = port100_abort_cmd,
+};
+
+static const struct usb_device_id port100_table[] = {
+       { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE,
+         .idVendor             = SONY_VENDOR_ID,
+         .idProduct            = RCS380_PRODUCT_ID,
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, port100_table);
+
+static int port100_probe(struct usb_interface *interface,
+                        const struct usb_device_id *id)
+{
+       struct port100 *dev;
+       int rc;
+
+       dev = devm_kzalloc(&interface->dev, sizeof(struct port100), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->udev = usb_get_dev(interface_to_usbdev(interface));
+       dev->interface = interface;
+       usb_set_intfdata(interface, dev);
+
+       nfc_info(&interface->dev, "Sony NFC Port-100 Series attached\n");
+
+       dev->nfc_digital_dev = nfc_digital_allocate_device(&port100_digital_ops,
+                                                          PORT100_PROTOCOLS,
+                                                          PORT100_CAPABILITIES,
+                                                          dev->skb_headroom,
+                                                          dev->skb_tailroom);
+       if (!dev->nfc_digital_dev) {
+               nfc_err(&interface->dev,
+                       "Could not allocate nfc_digital_dev.\n");
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       nfc_digital_set_parent_dev(dev->nfc_digital_dev, &interface->dev);
+       nfc_digital_set_drvdata(dev->nfc_digital_dev, dev);
+
+       rc = nfc_digital_register_device(dev->nfc_digital_dev);
+       if (rc) {
+               nfc_err(&interface->dev,
+                       "Could not register digital device.\n");
+               goto free_nfc_dev;
+       }
+
+       return 0;
+
+free_nfc_dev:
+       nfc_digital_free_device(dev->nfc_digital_dev);
+
+error:
+       return rc;
+}
+
+static void port100_disconnect(struct usb_interface *interface)
+{
+       struct port100 *dev;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       nfc_digital_unregister_device(dev->nfc_digital_dev);
+       nfc_digital_free_device(dev->nfc_digital_dev);
+
+       nfc_info(&interface->dev, "Sony Port-100 NFC device disconnected");
+}
+
+static struct usb_driver port100_driver = {
+       .name =         "port100",
+       .probe =        port100_probe,
+       .disconnect =   port100_disconnect,
+       .id_table =     port100_table,
+};
+
+module_usb_driver(port100_driver);
+
+MODULE_DESCRIPTION("NFC Port-100 series usb driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");