Add support of ST NFC transceiver controlled over UART.

This driver registers with the digital LDisc UART
framework as an UART LDisc driver, and as a phy driver
with the ST NFC transceiver core framework.

Signed-off-by: Shikha Singh <shikha.si...@st.com>
---
 drivers/nfc/nfcst/Kconfig  |  17 +++++
 drivers/nfc/nfcst/Makefile |   3 +
 drivers/nfc/nfcst/uart.c   | 164 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 184 insertions(+)
 create mode 100644 drivers/nfc/nfcst/uart.c

diff --git a/drivers/nfc/nfcst/Kconfig b/drivers/nfc/nfcst/Kconfig
index 2c71aa2..70fec4f 100644
--- a/drivers/nfc/nfcst/Kconfig
+++ b/drivers/nfc/nfcst/Kconfig
@@ -15,3 +15,20 @@ config NFC_ST
 
          Say Y here to compile support for ST NFC transceiver core
          framework into the kernel or say M to compile it as module.
+
+config NFC_ST_UART
+       tristate "ST NFC-over-UART driver"
+       depends on NFC_DIGITAL && NFC_DIGITAL_UART
+       select NFC_ST
+       help
+         ST NFC-over-UART driver.
+
+         This driver is an UART LDisc driver that helps
+         ST NFC transceiver core framework communicate with
+         the transceiver device over the UART interface.
+         The driver registers as a phy driver with the core,
+         and as an LDisc driver with the digital UART LDisc
+         framework.
+
+         Say Y here to compile support for ST NFC-over-UART driver
+         into the kernel or say M to compile it as module.
diff --git a/drivers/nfc/nfcst/Makefile b/drivers/nfc/nfcst/Makefile
index d46acc5..a90055a 100644
--- a/drivers/nfc/nfcst/Makefile
+++ b/drivers/nfc/nfcst/Makefile
@@ -4,3 +4,6 @@
 
 nfcst-y += core.o
 obj-$(CONFIG_NFC_ST) += nfcst.o
+
+nfcst_uart-y += uart.o
+obj-$(CONFIG_NFC_ST_UART) += nfcst_uart.o
diff --git a/drivers/nfc/nfcst/uart.c b/drivers/nfc/nfcst/uart.c
new file mode 100644
index 0000000..953281d
--- /dev/null
+++ b/drivers/nfc/nfcst/uart.c
@@ -0,0 +1,164 @@
+/*
+ * --------------------------------------------------------------------
+ * LDisc UART Driver for ST NFC Transceiver
+ * --------------------------------------------------------------------
+ * Copyright (C) 2016 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/module.h>
+#include <linux/of.h>
+#include <net/nfc/digital_uart.h>
+#include "stnfcdev.h"
+
+#define DEVICE_DEFAULT_BAUD 57600
+
+static unsigned int baud = DEVICE_DEFAULT_BAUD;
+
+static int nfcst_uart_digital_send(void *phy_ctx, struct sk_buff *skb)
+{
+       struct digital_uart *du = (struct digital_uart *)phy_ctx;
+
+       return du->ops.send(du, skb);
+}
+
+static struct nfcst_if_ops uart_ops = {
+       .phy_send = nfcst_uart_digital_send,
+};
+
+static int nfcst_uart_parse_dt(struct device_node *node,
+                              struct nfcst_pltf_data *pdata)
+{
+       struct device_node *matched_node;
+       const void *ptr;
+
+       matched_node = of_find_compatible_node(node, NULL, "st,nfc-uart");
+       if (!matched_node)
+               return -ENODEV;
+
+       ptr = of_get_property(matched_node, "st,baudrate", NULL);
+       if (!ptr)
+               return -ENODEV;
+
+       pdata->baudrate = be32_to_cpup(ptr);
+
+       return 0;
+}
+
+/*
+ * DIGITAL UART OPS
+ */
+static int nfcst_digital_uart_open(struct digital_uart *du)
+{
+       void *priv;
+       int err;
+       struct nfcst_pltf_data config;
+       struct nfcst_pltf_data *pdata = NULL;
+
+       if (du->tty->dev->parent && du->tty->dev->parent->of_node) {
+               err = nfcst_uart_parse_dt(du->tty->dev->parent->of_node,
+                                         &config);
+               if (err)
+                       dev_err(du->tty->dev, "No st nfc uart platform data 
found in DT\n");
+               else
+                       pdata = &config;
+       }
+
+       if (!pdata) {
+               dev_info(du->tty->dev, "No platform data / DT -> fallback to 
module params\n");
+               config.baudrate = baud;
+               pdata = &config;
+       }
+       priv = nfcst_register_phy(PHY_UART, (void *)du, &uart_ops,
+                                 du->tty->dev, pdata);
+       if (IS_ERR(priv))
+               return PTR_ERR(priv);
+
+       du->drv_data = priv;
+
+       /* set the default configuration */
+       digital_uart_set_config(du,
+                               DEVICE_DEFAULT_BAUD,
+                               0,
+                               DIGITAL_UART_STOP_BIT_2);
+
+       return 0;
+}
+
+static void nfcst_digital_uart_close(struct digital_uart *du)
+{
+       nfcst_unregister_phy(du->drv_data);
+}
+
+static int nfcst_digital_uart_recv(struct digital_uart *du, struct sk_buff 
*skb)
+{
+       return nfcst_recv_frame(du->drv_data, skb);
+}
+
+static int nfcst_digital_uart_recv_hdr_len(struct digital_uart *du,
+                                          const u8 *data,
+                                          int count)
+{
+       return nfcst_recv_hdr_len(du->drv_data, data, count);
+}
+
+static int nfcst_digital_uart_fr_len(struct digital_uart *du,
+                                    const u8 *data,
+                                    int count)
+{
+       return nfcst_recv_fr_len(du->drv_data, data, count);
+}
+
+static int nfcst_digital_uart_max_fr_sz(struct digital_uart *du)
+{
+       return nfcst_recv_max_fr_sz(du->drv_data);
+}
+
+static struct digital_uart nfcst_uart = {
+       .owner  = THIS_MODULE,
+       .name   = "nfcst_uart",
+       .driver = DIGITAL_UART_DRIVER_ST,
+       .ops    = {
+               .open           = nfcst_digital_uart_open,
+               .close          = nfcst_digital_uart_close,
+               .recv           = nfcst_digital_uart_recv,
+               .recv_fr_hdr_sz = nfcst_digital_uart_recv_hdr_len,
+               .recv_pl_sz     = nfcst_digital_uart_fr_len,
+               .recv_fr_max_sz = nfcst_digital_uart_max_fr_sz,
+       }
+};
+
+/*
+ * Module init
+ */
+static int nfcst_uart_init_module(void)
+{
+       return digital_uart_register(&nfcst_uart);
+}
+
+static void nfcst_uart_exit_module(void)
+{
+       digital_uart_unregister(&nfcst_uart);
+}
+
+module_init(nfcst_uart_init_module);
+module_exit(nfcst_uart_exit_module);
+
+MODULE_AUTHOR("Sudeep Biswas <sudeep.bis...@st.com>");
+MODULE_AUTHOR("Shikha Singh <shikha.si...@st.com>");
+MODULE_DESCRIPTION("ST NFC-over-UART");
+MODULE_LICENSE("GPL v2");
+
+module_param(baud, uint, 0000);
+MODULE_PARM_DESC(baud, "Tell the UART baudrate for communication");
-- 
1.8.2.1

Reply via email to