All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Andreas Färber" <afaerber@suse.de>
To: netdev@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org,
	"Jian-Hong Pan" <starnight@g.ncu.edu.tw>,
	"Jiri Pirko" <jiri@resnulli.us>,
	"Marcel Holtmann" <marcel@holtmann.org>,
	"David S . Miller" <davem@davemloft.net>,
	"Matthias Brugger" <mbrugger@suse.com>,
	"Janus Piwek" <jpiwek@arroweurope.com>,
	"Michael Röder" <michael.roeder@avnet.eu>,
	"Dollar Chen" <dollar.chen@wtmec.com>,
	"Ken Yu" <ken.yu@rakwireless.com>,
	"Andreas Färber" <afaerber@suse.de>
Subject: [RFC net-next 10/15] net: lora: Add Microchip RN2483
Date: Sun,  1 Jul 2018 13:07:59 +0200	[thread overview]
Message-ID: <20180701110804.32415-11-afaerber@suse.de> (raw)
In-Reply-To: <20180701110804.32415-1-afaerber@suse.de>

The Microchip RN2483 and RN2903 are UART based modules exposing both
LoRaWAN and LoRa. The RN2483 supports switching between 433 and 868 MHz.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/net/lora/Kconfig      |   7 +
 drivers/net/lora/Makefile     |   4 +
 drivers/net/lora/rn2483.c     | 344 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/lora/rn2483.h     |  40 +++++
 drivers/net/lora/rn2483_cmd.c | 130 ++++++++++++++++
 5 files changed, 525 insertions(+)
 create mode 100644 drivers/net/lora/rn2483.c
 create mode 100644 drivers/net/lora/rn2483.h
 create mode 100644 drivers/net/lora/rn2483_cmd.c

diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
index 0436f6b09a1c..940bd2cbe106 100644
--- a/drivers/net/lora/Kconfig
+++ b/drivers/net/lora/Kconfig
@@ -17,6 +17,13 @@ config LORA_DEV
 
 if LORA_DEV
 
+config LORA_RN2483
+	tristate "Microchip RN2483/RN2903 driver"
+	default y
+	depends on SERIAL_DEV_BUS
+	help
+	  Microchip RN2483/2903
+
 config LORA_SX1276
 	tristate "Semtech SX127x SPI driver"
 	default y
diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile
index 8845542dba50..07839c3ce9f8 100644
--- a/drivers/net/lora/Makefile
+++ b/drivers/net/lora/Makefile
@@ -9,5 +9,9 @@ lora-dev-y := dev.o
 # Alphabetically sorted.
 #
 
+obj-$(CONFIG_LORA_RN2483) += lora-rn2483.o
+lora-rn2483-y := rn2483.o
+lora-rn2483-y += rn2483_cmd.o
+
 obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o
 lora-sx1276-y := sx1276.o
diff --git a/drivers/net/lora/rn2483.c b/drivers/net/lora/rn2483.c
new file mode 100644
index 000000000000..8b9ec2575ee2
--- /dev/null
+++ b/drivers/net/lora/rn2483.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip RN2483/RN2903
+ *
+ * Copyright (c) 2017-2018 Andreas Färber
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/lora.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+#include "rn2483.h"
+
+struct rn2483_priv {
+	struct lora_priv lora;
+};
+
+static netdev_tx_t rn2483_loradev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	if (skb->protocol != htons(ETH_P_LORA)) {
+		kfree_skb(skb);
+		netdev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+
+	netif_stop_queue(netdev);
+
+	/* TODO */
+	return NETDEV_TX_OK;
+}
+
+static int rn2483_loradev_open(struct net_device *netdev)
+{
+	int ret;
+
+	netdev_dbg(netdev, "%s", __func__);
+
+	ret = open_loradev(netdev);
+	if (ret)
+		return ret;
+
+	netif_start_queue(netdev);
+
+	return 0;
+}
+
+static int rn2483_loradev_stop(struct net_device *netdev)
+{
+	netdev_dbg(netdev, "%s", __func__);
+
+	netif_stop_queue(netdev);
+	close_loradev(netdev);
+
+	return 0;
+}
+
+static const struct net_device_ops rn2483_net_device_ops = {
+	.ndo_open = rn2483_loradev_open,
+	.ndo_stop = rn2483_loradev_stop,
+	.ndo_start_xmit = rn2483_loradev_start_xmit,
+};
+
+int rn2483_readline_timeout(struct rn2483_device *rndev, char **line, unsigned long timeout)
+{
+	timeout = wait_for_completion_timeout(&rndev->line_recv_comp, timeout);
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	*line = devm_kstrdup(&rndev->serdev->dev, rndev->buf, GFP_KERNEL);
+	complete(&rndev->line_read_comp);
+	if (!*line)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void rn2483_receive_line(struct rn2483_device *rndev, const char *sz, size_t len)
+{
+	dev_dbg(&rndev->serdev->dev, "Received line '%s' (%d)", sz, (int)len);
+
+	reinit_completion(&rndev->line_read_comp);
+	complete(&rndev->line_recv_comp);
+	wait_for_completion(&rndev->line_read_comp);
+	reinit_completion(&rndev->line_recv_comp);
+}
+
+static int rn2483_receive_buf(struct serdev_device *serdev, const u8 *data, size_t count)
+{
+	struct rn2483_device *rndev = serdev_device_get_drvdata(serdev);
+	size_t i;
+
+	dev_dbg(&serdev->dev, "Receive (%d)", (int)count);
+	if (!rndev->buf) {
+		rndev->buf = devm_kmalloc(&serdev->dev, count, GFP_KERNEL);
+		if (!rndev->buf)
+			return 0;
+		rndev->buflen = 0;
+	} else {
+		void *tmp = devm_kmalloc(&serdev->dev, rndev->buflen + count, GFP_KERNEL);
+		if (!tmp)
+			return 0;
+		memcpy(tmp, rndev->buf, rndev->buflen);
+		devm_kfree(&serdev->dev, rndev->buf);
+		rndev->buf = tmp;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (data[i] == '\r') {
+			rndev->saw_cr = true;
+		} else if (data[i] == '\n' && rndev->saw_cr) {
+			if (i > 1)
+				memcpy(rndev->buf + rndev->buflen, data, i - 1);
+			((char *)rndev->buf)[rndev->buflen + i - 1] = 0;
+			rn2483_receive_line(rndev, rndev->buf, rndev->buflen + i - 1);
+			rndev->saw_cr = false;
+			devm_kfree(&serdev->dev, rndev->buf);
+			rndev->buf = NULL;
+			rndev->buflen = 0;
+			return i + 1;
+		} else
+			rndev->saw_cr = false;
+	}
+
+	memcpy(rndev->buf + rndev->buflen, data, count);
+	rndev->buflen += count;
+	return count;
+}
+
+static const struct serdev_device_ops rn2483_serdev_client_ops = {
+	.receive_buf = rn2483_receive_buf,
+};
+
+static int rn2483_probe(struct serdev_device *sdev)
+{
+	struct rn2483_device *rndev;
+	char *line, *cmd;
+	char sz[5];
+	u32 status;
+	int ret;
+
+	dev_info(&sdev->dev, "Probing");
+
+	rndev = devm_kzalloc(&sdev->dev, sizeof(struct rn2483_device), GFP_KERNEL);
+	if (!rndev)
+		return -ENOMEM;
+
+	rndev->serdev = sdev;
+	init_completion(&rndev->line_recv_comp);
+	init_completion(&rndev->line_read_comp);
+	mutex_init(&rndev->cmd_lock);
+	serdev_device_set_drvdata(sdev, rndev);
+
+	rndev->reset_gpio = devm_gpiod_get_optional(&sdev->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(rndev->reset_gpio))
+		return PTR_ERR(rndev->reset_gpio);
+
+	ret = serdev_device_open(sdev);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to open (%d)", ret);
+		return ret;
+	}
+
+	serdev_device_set_baudrate(sdev, 57600);
+	serdev_device_set_flow_control(sdev, false);
+
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+	msleep(5);
+	serdev_device_set_client_ops(sdev, &rn2483_serdev_client_ops);
+	gpiod_set_value_cansleep(rndev->reset_gpio, 1);
+	msleep(100);
+
+	ret = rn2483_readline_timeout(rndev, &line, HZ);
+	if (ret) {
+		if (ret != -ENOMEM)
+			dev_err(&sdev->dev, "Timeout waiting for firmware identification");
+		goto err_timeout;
+	}
+
+	if (strlen(line) < strlen("RNxxxx X.Y.Z MMM DD YYYY HH:MM:SS") || line[6] != ' ' ||
+			strncmp(line, "RN", 2) != 0) {
+		dev_err(&sdev->dev, "Unexpected response '%s'", line);
+		devm_kfree(&sdev->dev, line);
+		ret = -EINVAL;
+		goto err_version;
+	}
+	dev_info(&sdev->dev, "Firmware '%s'", line);
+	strncpy(sz, line + 2, 4);
+	sz[4] = 0;
+	devm_kfree(&sdev->dev, line);
+	ret = kstrtouint(sz, 10, &rndev->model);
+	if (ret)
+		goto err_model;
+	if (!(rndev->model == 2483 || rndev->model == 2903)) {
+		dev_err(&sdev->dev, "Unknown model %u", rndev->model);
+		ret = -ENOTSUPP;
+		goto err_model;
+	}
+	dev_info(&sdev->dev, "Detected RN%u", rndev->model);
+
+	ret = rn2483_sys_get_hweui(rndev, &rndev->hweui);
+	if (ret) {
+		if (ret != -ENOMEM)
+			dev_err(&sdev->dev, "Failed to read HWEUI (%d)", ret);
+		goto err_hweui;
+	}
+	dev_info(&sdev->dev, "HWEUI " PRIxLORAEUI, LORA_EUI(rndev->hweui));
+
+	switch (rndev->model) {
+	case 2483:
+		ret = rn2483_mac_get_band(rndev, &rndev->band);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to read band (%d)", ret);
+			goto err_band;
+		}
+		dev_info(&sdev->dev, "Frequency band %u MHz", rndev->band);
+
+		ret = rn2483_mac_reset_band(rndev, 433);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to reset band (%d)", ret);
+			goto err_band;
+		}
+		rndev->band = 433;
+
+		ret = rn2483_mac_get_band(rndev, &rndev->band);
+		if (!ret)
+			dev_info(&sdev->dev, "New frequency band: %u MHz", rndev->band);
+		break;
+	case 2903:
+		/* No "mac get band" command available */
+		rndev->band = 915;
+		break;
+	}
+
+	ret = rn2483_mac_get_status(rndev, &status);
+	if (!ret)
+		dev_info(&sdev->dev, "MAC status %08x", status);
+
+	if (true) {
+		u32 pause;
+		ret = rn2483_mac_pause(rndev, &pause);
+		if (!ret)
+			dev_info(&sdev->dev, "MAC pausing (0x%08x)", pause);
+		ret = rn2483_mac_resume(rndev);
+		if (!ret)
+			dev_info(&sdev->dev, "MAC resuming");
+	}
+
+	cmd = "mac get sync";
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, cmd, &line, HZ);
+	mutex_unlock(&rndev->cmd_lock);
+	if (!ret) {
+		dev_info(&sdev->dev, "%s => '%s'", cmd, line);
+		devm_kfree(&sdev->dev, line);
+	}
+
+	rndev->netdev = alloc_loradev(sizeof(struct rn2483_priv));
+	if (!rndev->netdev) {
+		ret = -ENOMEM;
+		goto err_alloc_netdev;
+	}
+
+	rndev->netdev->netdev_ops = &rn2483_net_device_ops;
+	SET_NETDEV_DEV(rndev->netdev, &sdev->dev);
+
+	ret = register_loradev(rndev->netdev);
+	if (ret)
+		goto err_register_netdev;
+
+	dev_info(&sdev->dev, "Done.");
+
+	return 0;
+
+err_register_netdev:
+	free_loradev(rndev->netdev);
+err_alloc_netdev:
+err_band:
+err_hweui:
+err_model:
+err_version:
+err_timeout:
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+	return ret;
+}
+
+static void rn2483_remove(struct serdev_device *sdev)
+{
+	struct rn2483_device *rndev = serdev_device_get_drvdata(sdev);
+
+	unregister_loradev(rndev->netdev);
+	free_loradev(rndev->netdev);
+
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+
+	complete(&rndev->line_read_comp);
+
+	serdev_device_close(sdev);
+
+	dev_info(&sdev->dev, "Removed");
+}
+
+static const struct of_device_id rn2483_of_match[] = {
+	{ .compatible = "microchip,rn2483" },
+	{ .compatible = "microchip,rn2903" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rn2483_of_match);
+
+static struct serdev_device_driver rn2483_serdev_driver = {
+	.probe = rn2483_probe,
+	.remove = rn2483_remove,
+	.driver = {
+		.name = "rn2483",
+		.of_match_table = rn2483_of_match,
+	},
+};
+
+static int __init rn2483_init(void)
+{
+	int ret;
+
+	ret = serdev_device_driver_register(&rn2483_serdev_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit rn2483_exit(void)
+{
+	serdev_device_driver_unregister(&rn2483_serdev_driver);
+}
+
+module_init(rn2483_init);
+module_exit(rn2483_exit);
+
+MODULE_DESCRIPTION("RN2483 serdev driver");
+MODULE_AUTHOR("Andreas Färber <afaerber@suse.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/lora/rn2483.h b/drivers/net/lora/rn2483.h
new file mode 100644
index 000000000000..f92660286f15
--- /dev/null
+++ b/drivers/net/lora/rn2483.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2017-2018 Andreas Färber
+ */
+#ifndef _RN2483_H
+#define _RN2483_H
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/netdevice.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+struct rn2483_device {
+	struct serdev_device *serdev;
+	struct gpio_desc *reset_gpio;
+	struct net_device *netdev;
+	unsigned model;
+	lora_eui hweui;
+	unsigned band;
+	bool saw_cr;
+	void *buf;
+	size_t buflen;
+	struct completion line_recv_comp;
+	struct completion line_read_comp;
+	struct mutex cmd_lock;
+};
+
+int rn2483_readline_timeout(struct rn2483_device *rndev, char **line, unsigned long timeout);
+int rn2483_send_command_timeout(struct rn2483_device *rndev,
+	const char *cmd, char **resp, unsigned long timeout);
+
+int rn2483_sys_get_hweui(struct rn2483_device *rndev, lora_eui *val);
+int rn2483_mac_get_band(struct rn2483_device *rndev, uint *val);
+int rn2483_mac_get_status(struct rn2483_device *rndev, u32 *val);
+int rn2483_mac_reset_band(struct rn2483_device *rndev, unsigned band);
+int rn2483_mac_pause(struct rn2483_device *rndev, u32 *max_pause);
+int rn2483_mac_resume(struct rn2483_device *rndev);
+
+#endif
diff --git a/drivers/net/lora/rn2483_cmd.c b/drivers/net/lora/rn2483_cmd.c
new file mode 100644
index 000000000000..6d6fca8fa93c
--- /dev/null
+++ b/drivers/net/lora/rn2483_cmd.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip RN2483/RN2903 - UART commands
+ *
+ * Copyright (c) 2017-2018 Andreas Färber
+ */
+#include "rn2483.h"
+
+#define RN2483_CMD_TIMEOUT HZ
+
+int rn2483_send_command_timeout(struct rn2483_device *rndev,
+	const char *cmd, char **resp, unsigned long timeout)
+{
+	int ret;
+
+	ret = serdev_device_write_buf(rndev->serdev, cmd, strlen(cmd));
+	if (ret < 0)
+		return ret;
+
+	ret = serdev_device_write_buf(rndev->serdev, "\r\n", 2);
+	if (ret < 0)
+		return ret;
+
+	return rn2483_readline_timeout(rndev, resp, timeout);
+}
+
+int rn2483_sys_get_hweui(struct rn2483_device *rndev, lora_eui *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "sys get hweui", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = lora_strtoeui(line, val);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_get_band(struct rn2483_device *rndev, uint *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac get band", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtouint(line, 10, val);
+	devm_kfree(&rndev->serdev->dev, line);
+
+	return ret;
+}
+
+int rn2483_mac_get_status(struct rn2483_device *rndev, u32 *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac get status", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtou32(line, 16, val);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_reset_band(struct rn2483_device *rndev, unsigned band)
+{
+	int ret;
+	char *line, *cmd;
+
+	cmd = devm_kasprintf(&rndev->serdev->dev, GFP_KERNEL, "mac reset %u", band);
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, cmd, &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	devm_kfree(&rndev->serdev->dev, cmd);
+	if (ret)
+		return ret;
+
+	if (strcmp(line, "ok") == 0)
+		ret = 0;
+	else if (strcmp(line, "invalid_param") == 0)
+		ret = -EINVAL;
+	else
+		ret = -EPROTO;
+
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_pause(struct rn2483_device *rndev, u32 *max_pause)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac pause", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtou32(line, 10, max_pause);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_resume(struct rn2483_device *rndev)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac resume", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = (strcmp(line, "ok") == 0) ? 0 : -EPROTO;
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
-- 
2.16.4


WARNING: multiple messages have this Message-ID (diff)
From: afaerber@suse.de (Andreas Färber)
To: linux-arm-kernel@lists.infradead.org
Subject: [RFC net-next 10/15] net: lora: Add Microchip RN2483
Date: Sun,  1 Jul 2018 13:07:59 +0200	[thread overview]
Message-ID: <20180701110804.32415-11-afaerber@suse.de> (raw)
In-Reply-To: <20180701110804.32415-1-afaerber@suse.de>

The Microchip RN2483 and RN2903 are UART based modules exposing both
LoRaWAN and LoRa. The RN2483 supports switching between 433 and 868 MHz.

Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 drivers/net/lora/Kconfig      |   7 +
 drivers/net/lora/Makefile     |   4 +
 drivers/net/lora/rn2483.c     | 344 ++++++++++++++++++++++++++++++++++++++++++
 drivers/net/lora/rn2483.h     |  40 +++++
 drivers/net/lora/rn2483_cmd.c | 130 ++++++++++++++++
 5 files changed, 525 insertions(+)
 create mode 100644 drivers/net/lora/rn2483.c
 create mode 100644 drivers/net/lora/rn2483.h
 create mode 100644 drivers/net/lora/rn2483_cmd.c

diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig
index 0436f6b09a1c..940bd2cbe106 100644
--- a/drivers/net/lora/Kconfig
+++ b/drivers/net/lora/Kconfig
@@ -17,6 +17,13 @@ config LORA_DEV
 
 if LORA_DEV
 
+config LORA_RN2483
+	tristate "Microchip RN2483/RN2903 driver"
+	default y
+	depends on SERIAL_DEV_BUS
+	help
+	  Microchip RN2483/2903
+
 config LORA_SX1276
 	tristate "Semtech SX127x SPI driver"
 	default y
diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile
index 8845542dba50..07839c3ce9f8 100644
--- a/drivers/net/lora/Makefile
+++ b/drivers/net/lora/Makefile
@@ -9,5 +9,9 @@ lora-dev-y := dev.o
 # Alphabetically sorted.
 #
 
+obj-$(CONFIG_LORA_RN2483) += lora-rn2483.o
+lora-rn2483-y := rn2483.o
+lora-rn2483-y += rn2483_cmd.o
+
 obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o
 lora-sx1276-y := sx1276.o
diff --git a/drivers/net/lora/rn2483.c b/drivers/net/lora/rn2483.c
new file mode 100644
index 000000000000..8b9ec2575ee2
--- /dev/null
+++ b/drivers/net/lora/rn2483.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip RN2483/RN2903
+ *
+ * Copyright (c) 2017-2018 Andreas F?rber
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/lora.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+#include "rn2483.h"
+
+struct rn2483_priv {
+	struct lora_priv lora;
+};
+
+static netdev_tx_t rn2483_loradev_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	if (skb->protocol != htons(ETH_P_LORA)) {
+		kfree_skb(skb);
+		netdev->stats.tx_dropped++;
+		return NETDEV_TX_OK;
+	}
+
+	netif_stop_queue(netdev);
+
+	/* TODO */
+	return NETDEV_TX_OK;
+}
+
+static int rn2483_loradev_open(struct net_device *netdev)
+{
+	int ret;
+
+	netdev_dbg(netdev, "%s", __func__);
+
+	ret = open_loradev(netdev);
+	if (ret)
+		return ret;
+
+	netif_start_queue(netdev);
+
+	return 0;
+}
+
+static int rn2483_loradev_stop(struct net_device *netdev)
+{
+	netdev_dbg(netdev, "%s", __func__);
+
+	netif_stop_queue(netdev);
+	close_loradev(netdev);
+
+	return 0;
+}
+
+static const struct net_device_ops rn2483_net_device_ops = {
+	.ndo_open = rn2483_loradev_open,
+	.ndo_stop = rn2483_loradev_stop,
+	.ndo_start_xmit = rn2483_loradev_start_xmit,
+};
+
+int rn2483_readline_timeout(struct rn2483_device *rndev, char **line, unsigned long timeout)
+{
+	timeout = wait_for_completion_timeout(&rndev->line_recv_comp, timeout);
+	if (!timeout)
+		return -ETIMEDOUT;
+
+	*line = devm_kstrdup(&rndev->serdev->dev, rndev->buf, GFP_KERNEL);
+	complete(&rndev->line_read_comp);
+	if (!*line)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void rn2483_receive_line(struct rn2483_device *rndev, const char *sz, size_t len)
+{
+	dev_dbg(&rndev->serdev->dev, "Received line '%s' (%d)", sz, (int)len);
+
+	reinit_completion(&rndev->line_read_comp);
+	complete(&rndev->line_recv_comp);
+	wait_for_completion(&rndev->line_read_comp);
+	reinit_completion(&rndev->line_recv_comp);
+}
+
+static int rn2483_receive_buf(struct serdev_device *serdev, const u8 *data, size_t count)
+{
+	struct rn2483_device *rndev = serdev_device_get_drvdata(serdev);
+	size_t i;
+
+	dev_dbg(&serdev->dev, "Receive (%d)", (int)count);
+	if (!rndev->buf) {
+		rndev->buf = devm_kmalloc(&serdev->dev, count, GFP_KERNEL);
+		if (!rndev->buf)
+			return 0;
+		rndev->buflen = 0;
+	} else {
+		void *tmp = devm_kmalloc(&serdev->dev, rndev->buflen + count, GFP_KERNEL);
+		if (!tmp)
+			return 0;
+		memcpy(tmp, rndev->buf, rndev->buflen);
+		devm_kfree(&serdev->dev, rndev->buf);
+		rndev->buf = tmp;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (data[i] == '\r') {
+			rndev->saw_cr = true;
+		} else if (data[i] == '\n' && rndev->saw_cr) {
+			if (i > 1)
+				memcpy(rndev->buf + rndev->buflen, data, i - 1);
+			((char *)rndev->buf)[rndev->buflen + i - 1] = 0;
+			rn2483_receive_line(rndev, rndev->buf, rndev->buflen + i - 1);
+			rndev->saw_cr = false;
+			devm_kfree(&serdev->dev, rndev->buf);
+			rndev->buf = NULL;
+			rndev->buflen = 0;
+			return i + 1;
+		} else
+			rndev->saw_cr = false;
+	}
+
+	memcpy(rndev->buf + rndev->buflen, data, count);
+	rndev->buflen += count;
+	return count;
+}
+
+static const struct serdev_device_ops rn2483_serdev_client_ops = {
+	.receive_buf = rn2483_receive_buf,
+};
+
+static int rn2483_probe(struct serdev_device *sdev)
+{
+	struct rn2483_device *rndev;
+	char *line, *cmd;
+	char sz[5];
+	u32 status;
+	int ret;
+
+	dev_info(&sdev->dev, "Probing");
+
+	rndev = devm_kzalloc(&sdev->dev, sizeof(struct rn2483_device), GFP_KERNEL);
+	if (!rndev)
+		return -ENOMEM;
+
+	rndev->serdev = sdev;
+	init_completion(&rndev->line_recv_comp);
+	init_completion(&rndev->line_read_comp);
+	mutex_init(&rndev->cmd_lock);
+	serdev_device_set_drvdata(sdev, rndev);
+
+	rndev->reset_gpio = devm_gpiod_get_optional(&sdev->dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(rndev->reset_gpio))
+		return PTR_ERR(rndev->reset_gpio);
+
+	ret = serdev_device_open(sdev);
+	if (ret) {
+		dev_err(&sdev->dev, "Failed to open (%d)", ret);
+		return ret;
+	}
+
+	serdev_device_set_baudrate(sdev, 57600);
+	serdev_device_set_flow_control(sdev, false);
+
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+	msleep(5);
+	serdev_device_set_client_ops(sdev, &rn2483_serdev_client_ops);
+	gpiod_set_value_cansleep(rndev->reset_gpio, 1);
+	msleep(100);
+
+	ret = rn2483_readline_timeout(rndev, &line, HZ);
+	if (ret) {
+		if (ret != -ENOMEM)
+			dev_err(&sdev->dev, "Timeout waiting for firmware identification");
+		goto err_timeout;
+	}
+
+	if (strlen(line) < strlen("RNxxxx X.Y.Z MMM DD YYYY HH:MM:SS") || line[6] != ' ' ||
+			strncmp(line, "RN", 2) != 0) {
+		dev_err(&sdev->dev, "Unexpected response '%s'", line);
+		devm_kfree(&sdev->dev, line);
+		ret = -EINVAL;
+		goto err_version;
+	}
+	dev_info(&sdev->dev, "Firmware '%s'", line);
+	strncpy(sz, line + 2, 4);
+	sz[4] = 0;
+	devm_kfree(&sdev->dev, line);
+	ret = kstrtouint(sz, 10, &rndev->model);
+	if (ret)
+		goto err_model;
+	if (!(rndev->model == 2483 || rndev->model == 2903)) {
+		dev_err(&sdev->dev, "Unknown model %u", rndev->model);
+		ret = -ENOTSUPP;
+		goto err_model;
+	}
+	dev_info(&sdev->dev, "Detected RN%u", rndev->model);
+
+	ret = rn2483_sys_get_hweui(rndev, &rndev->hweui);
+	if (ret) {
+		if (ret != -ENOMEM)
+			dev_err(&sdev->dev, "Failed to read HWEUI (%d)", ret);
+		goto err_hweui;
+	}
+	dev_info(&sdev->dev, "HWEUI " PRIxLORAEUI, LORA_EUI(rndev->hweui));
+
+	switch (rndev->model) {
+	case 2483:
+		ret = rn2483_mac_get_band(rndev, &rndev->band);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to read band (%d)", ret);
+			goto err_band;
+		}
+		dev_info(&sdev->dev, "Frequency band %u MHz", rndev->band);
+
+		ret = rn2483_mac_reset_band(rndev, 433);
+		if (ret) {
+			dev_err(&sdev->dev, "Failed to reset band (%d)", ret);
+			goto err_band;
+		}
+		rndev->band = 433;
+
+		ret = rn2483_mac_get_band(rndev, &rndev->band);
+		if (!ret)
+			dev_info(&sdev->dev, "New frequency band: %u MHz", rndev->band);
+		break;
+	case 2903:
+		/* No "mac get band" command available */
+		rndev->band = 915;
+		break;
+	}
+
+	ret = rn2483_mac_get_status(rndev, &status);
+	if (!ret)
+		dev_info(&sdev->dev, "MAC status %08x", status);
+
+	if (true) {
+		u32 pause;
+		ret = rn2483_mac_pause(rndev, &pause);
+		if (!ret)
+			dev_info(&sdev->dev, "MAC pausing (0x%08x)", pause);
+		ret = rn2483_mac_resume(rndev);
+		if (!ret)
+			dev_info(&sdev->dev, "MAC resuming");
+	}
+
+	cmd = "mac get sync";
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, cmd, &line, HZ);
+	mutex_unlock(&rndev->cmd_lock);
+	if (!ret) {
+		dev_info(&sdev->dev, "%s => '%s'", cmd, line);
+		devm_kfree(&sdev->dev, line);
+	}
+
+	rndev->netdev = alloc_loradev(sizeof(struct rn2483_priv));
+	if (!rndev->netdev) {
+		ret = -ENOMEM;
+		goto err_alloc_netdev;
+	}
+
+	rndev->netdev->netdev_ops = &rn2483_net_device_ops;
+	SET_NETDEV_DEV(rndev->netdev, &sdev->dev);
+
+	ret = register_loradev(rndev->netdev);
+	if (ret)
+		goto err_register_netdev;
+
+	dev_info(&sdev->dev, "Done.");
+
+	return 0;
+
+err_register_netdev:
+	free_loradev(rndev->netdev);
+err_alloc_netdev:
+err_band:
+err_hweui:
+err_model:
+err_version:
+err_timeout:
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+	return ret;
+}
+
+static void rn2483_remove(struct serdev_device *sdev)
+{
+	struct rn2483_device *rndev = serdev_device_get_drvdata(sdev);
+
+	unregister_loradev(rndev->netdev);
+	free_loradev(rndev->netdev);
+
+	gpiod_set_value_cansleep(rndev->reset_gpio, 0);
+
+	complete(&rndev->line_read_comp);
+
+	serdev_device_close(sdev);
+
+	dev_info(&sdev->dev, "Removed");
+}
+
+static const struct of_device_id rn2483_of_match[] = {
+	{ .compatible = "microchip,rn2483" },
+	{ .compatible = "microchip,rn2903" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rn2483_of_match);
+
+static struct serdev_device_driver rn2483_serdev_driver = {
+	.probe = rn2483_probe,
+	.remove = rn2483_remove,
+	.driver = {
+		.name = "rn2483",
+		.of_match_table = rn2483_of_match,
+	},
+};
+
+static int __init rn2483_init(void)
+{
+	int ret;
+
+	ret = serdev_device_driver_register(&rn2483_serdev_driver);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static void __exit rn2483_exit(void)
+{
+	serdev_device_driver_unregister(&rn2483_serdev_driver);
+}
+
+module_init(rn2483_init);
+module_exit(rn2483_exit);
+
+MODULE_DESCRIPTION("RN2483 serdev driver");
+MODULE_AUTHOR("Andreas F?rber <afaerber@suse.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/lora/rn2483.h b/drivers/net/lora/rn2483.h
new file mode 100644
index 000000000000..f92660286f15
--- /dev/null
+++ b/drivers/net/lora/rn2483.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2017-2018 Andreas F?rber
+ */
+#ifndef _RN2483_H
+#define _RN2483_H
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/netdevice.h>
+#include <linux/serdev.h>
+#include <linux/lora/dev.h>
+
+struct rn2483_device {
+	struct serdev_device *serdev;
+	struct gpio_desc *reset_gpio;
+	struct net_device *netdev;
+	unsigned model;
+	lora_eui hweui;
+	unsigned band;
+	bool saw_cr;
+	void *buf;
+	size_t buflen;
+	struct completion line_recv_comp;
+	struct completion line_read_comp;
+	struct mutex cmd_lock;
+};
+
+int rn2483_readline_timeout(struct rn2483_device *rndev, char **line, unsigned long timeout);
+int rn2483_send_command_timeout(struct rn2483_device *rndev,
+	const char *cmd, char **resp, unsigned long timeout);
+
+int rn2483_sys_get_hweui(struct rn2483_device *rndev, lora_eui *val);
+int rn2483_mac_get_band(struct rn2483_device *rndev, uint *val);
+int rn2483_mac_get_status(struct rn2483_device *rndev, u32 *val);
+int rn2483_mac_reset_band(struct rn2483_device *rndev, unsigned band);
+int rn2483_mac_pause(struct rn2483_device *rndev, u32 *max_pause);
+int rn2483_mac_resume(struct rn2483_device *rndev);
+
+#endif
diff --git a/drivers/net/lora/rn2483_cmd.c b/drivers/net/lora/rn2483_cmd.c
new file mode 100644
index 000000000000..6d6fca8fa93c
--- /dev/null
+++ b/drivers/net/lora/rn2483_cmd.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Microchip RN2483/RN2903 - UART commands
+ *
+ * Copyright (c) 2017-2018 Andreas F?rber
+ */
+#include "rn2483.h"
+
+#define RN2483_CMD_TIMEOUT HZ
+
+int rn2483_send_command_timeout(struct rn2483_device *rndev,
+	const char *cmd, char **resp, unsigned long timeout)
+{
+	int ret;
+
+	ret = serdev_device_write_buf(rndev->serdev, cmd, strlen(cmd));
+	if (ret < 0)
+		return ret;
+
+	ret = serdev_device_write_buf(rndev->serdev, "\r\n", 2);
+	if (ret < 0)
+		return ret;
+
+	return rn2483_readline_timeout(rndev, resp, timeout);
+}
+
+int rn2483_sys_get_hweui(struct rn2483_device *rndev, lora_eui *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "sys get hweui", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = lora_strtoeui(line, val);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_get_band(struct rn2483_device *rndev, uint *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac get band", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtouint(line, 10, val);
+	devm_kfree(&rndev->serdev->dev, line);
+
+	return ret;
+}
+
+int rn2483_mac_get_status(struct rn2483_device *rndev, u32 *val)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac get status", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtou32(line, 16, val);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_reset_band(struct rn2483_device *rndev, unsigned band)
+{
+	int ret;
+	char *line, *cmd;
+
+	cmd = devm_kasprintf(&rndev->serdev->dev, GFP_KERNEL, "mac reset %u", band);
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, cmd, &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	devm_kfree(&rndev->serdev->dev, cmd);
+	if (ret)
+		return ret;
+
+	if (strcmp(line, "ok") == 0)
+		ret = 0;
+	else if (strcmp(line, "invalid_param") == 0)
+		ret = -EINVAL;
+	else
+		ret = -EPROTO;
+
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_pause(struct rn2483_device *rndev, u32 *max_pause)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac pause", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = kstrtou32(line, 10, max_pause);
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
+
+int rn2483_mac_resume(struct rn2483_device *rndev)
+{
+	int ret;
+	char *line;
+
+	mutex_lock(&rndev->cmd_lock);
+	ret = rn2483_send_command_timeout(rndev, "mac resume", &line, RN2483_CMD_TIMEOUT);
+	mutex_unlock(&rndev->cmd_lock);
+	if (ret)
+		return ret;
+
+	ret = (strcmp(line, "ok") == 0) ? 0 : -EPROTO;
+	devm_kfree(&rndev->serdev->dev, line);
+	return ret;
+}
-- 
2.16.4

  parent reply	other threads:[~2018-07-01 11:10 UTC|newest]

Thread overview: 173+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-01 11:07 [RFC net-next 00/15] net: A socket API for LoRa Andreas Färber
2018-07-01 11:07 ` Andreas Färber
2018-07-01 11:07 ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 01/15] net: Reserve protocol numbers " Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 02/15] net: lora: Define sockaddr_lora Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 03/15] net: lora: Add protocol numbers Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 04/15] net: Add lora subsystem Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 05/15] HACK: net: lora: Deal with .poll_mask in 4.18-rc2 Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-02 16:22   ` Jiri Pirko
2018-07-02 16:22     ` Jiri Pirko
2018-07-02 16:59     ` Andreas Färber
2018-07-02 16:59       ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 06/15] net: lora: Prepare for device drivers Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 07/15] net: lora: Add Semtech SX1276 Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 12:02   ` Andreas Färber
2018-07-01 12:02     ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 08/15] net: lora: sx1276: Add debugfs Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-02 16:26   ` Jiri Pirko
2018-07-02 16:26     ` Jiri Pirko
2018-07-02 17:57     ` Andreas Färber
2018-07-02 17:57       ` Andreas Färber
2018-07-01 11:07 ` [RFC net-next 09/15] net: lora: Prepare EUI helpers Andreas Färber
2018-07-01 11:07   ` Andreas Färber
2018-07-01 11:07 ` Andreas Färber [this message]
2018-07-01 11:07   ` [RFC net-next 10/15] net: lora: Add Microchip RN2483 Andreas Färber
2018-07-01 11:08 ` [RFC net-next 11/15] net: lora: Add IMST WiMOD Andreas Färber
2018-07-01 11:08   ` Andreas Färber
2019-01-06 14:57   ` Heinrich Schuchardt
2019-01-06 14:57     ` Heinrich Schuchardt
2019-01-07 11:29     ` Andreas Färber
2019-01-07 11:29       ` Andreas Färber
2018-07-01 11:08 ` [RFC net-next 12/15] net: lora: Add USI WM-SG-SM-42 Andreas Färber
2018-07-01 11:08   ` Andreas Färber
2018-07-01 11:08 ` [RFC net-next 13/15] net: lora: Prepare RAK RAK811 Andreas Färber
2018-07-01 11:08   ` Andreas Färber
2018-07-01 11:08 ` [RFC net-next 14/15] net: lora: Prepare Semtech SX1257 Andreas Färber
2018-07-01 11:08   ` Andreas Färber
2018-07-01 11:08 ` [RFC net-next 15/15] net: lora: Add Semtech SX1301 Andreas Färber
2018-07-01 11:08   ` Andreas Färber
2018-07-02 11:51   ` Ben Whitten
2018-07-02 11:51     ` Ben Whitten
2018-07-03  3:01     ` Andreas Färber
2018-07-03  3:01       ` Andreas Färber
2018-07-05  8:59       ` Ben Whitten
2018-07-05  8:59         ` Ben Whitten
2018-07-05  8:59         ` Ben Whitten
2018-07-02 16:12   ` Mark Brown
2018-07-02 16:12     ` Mark Brown
2018-07-02 16:12     ` Mark Brown
2018-07-02 17:34     ` Andreas Färber
2018-07-02 17:34       ` Andreas Färber
2018-07-02 20:43       ` Ben Whitten
2018-07-02 20:43         ` Ben Whitten
2018-07-03  3:21         ` Andreas Färber
2018-07-03  3:21           ` Andreas Färber
2018-07-03  3:21           ` Andreas Färber
2018-07-05  8:43           ` Ben Whitten
2018-07-05  8:43             ` Ben Whitten
2018-07-05  8:43             ` Ben Whitten
2018-07-03 14:50       ` Mark Brown
2018-07-03 14:50         ` Mark Brown
2018-07-03 15:09         ` Andreas Färber
2018-07-03 15:09           ` Andreas Färber
2018-07-03 15:09           ` Andreas Färber
2018-07-03 15:31           ` Mark Brown
2018-07-03 15:31             ` Mark Brown
2018-07-03 15:31             ` Mark Brown
2018-07-03 16:40             ` Andreas Färber
2018-07-03 16:40               ` Andreas Färber
2018-07-04 11:43               ` Mark Brown
2018-07-04 11:43                 ` Mark Brown
2018-07-04 13:41                 ` Ben Whitten
2018-07-04 13:41                   ` Ben Whitten
2018-07-04 13:41                   ` Ben Whitten
2018-07-04 14:32                   ` Mark Brown
2018-07-04 14:32                     ` Mark Brown
2018-07-04 14:32                     ` Mark Brown
2018-07-03 15:11 ` [RFC net-next 00/15] net: A socket API for LoRa Jian-Hong Pan
2018-07-03 15:11   ` Jian-Hong Pan
2018-07-03 15:11   ` Jian-Hong Pan
2018-08-05  0:11   ` Andreas Färber
2018-08-05  0:11     ` Andreas Färber
2018-08-05  0:11     ` Andreas Färber
2018-08-08 20:36     ` Alan Cox
2018-08-08 20:36       ` Alan Cox
2018-08-08 20:36       ` Alan Cox
2018-08-08 22:42       ` Andreas Färber
2018-08-08 22:42         ` Andreas Färber
2018-08-08 22:42         ` Andreas Färber
2018-08-09 11:59         ` Alan Cox
2018-08-09 11:59           ` Alan Cox
2018-08-09 11:59           ` Alan Cox
2018-08-09 15:02           ` Jian-Hong Pan
2018-08-09 15:02             ` Jian-Hong Pan
2018-08-09 15:02             ` Jian-Hong Pan
2018-08-09 15:21             ` Alexander Aring
2018-08-09 15:21               ` Alexander Aring
2018-08-09 15:21               ` Alexander Aring
2018-08-10 15:57             ` Alan Cox
2018-08-10 15:57               ` Alan Cox
2018-08-10 15:57               ` Alan Cox
2018-08-11 18:30               ` Stefan Schmidt
2018-08-11 18:30                 ` Stefan Schmidt
2018-08-11 18:30                 ` Stefan Schmidt
2018-08-12 16:49                 ` Andreas Färber
2018-08-12 16:49                   ` Andreas Färber
2018-08-12 16:49                   ` Andreas Färber
2018-08-12 16:37               ` Jian-Hong Pan
2018-08-12 16:37                 ` Jian-Hong Pan
2018-08-12 16:37                 ` Jian-Hong Pan
2018-08-12 17:59                 ` Andreas Färber
2018-08-12 17:59                   ` Andreas Färber
2018-08-12 17:59                   ` Andreas Färber
2018-08-13 12:36                   ` Alan Cox
2018-08-13 12:36                     ` Alan Cox
2018-08-13 12:36                     ` Alan Cox
2018-08-09 15:12           ` Alexander Aring
2018-08-09 15:12             ` Alexander Aring
2018-08-09 15:12             ` Alexander Aring
2018-08-09 15:12             ` Alexander Aring
2018-08-09  0:50     ` Andreas Färber
2018-08-09  0:50       ` Andreas Färber
2018-08-09  0:50       ` Andreas Färber
2018-07-04 18:26 ` Stefan Schmidt
2018-07-04 18:26   ` Stefan Schmidt
2018-07-04 18:26   ` Stefan Schmidt
2018-07-05 10:43   ` Helmut Tschemernjak
2018-07-05 10:43     ` Helmut Tschemernjak
2018-07-05 10:43     ` Helmut Tschemernjak
2018-07-11  2:07     ` Andreas Färber
2018-07-11  2:07       ` Andreas Färber
2018-07-11  2:07       ` Andreas Färber
2018-07-11 11:45       ` Helmut Tschemernjak
2018-07-11 11:45         ` Helmut Tschemernjak
2018-07-11 11:45         ` Helmut Tschemernjak
2018-07-11 15:21 ` Ben Whitten
2018-07-11 15:21   ` Ben Whitten
2018-07-11 15:21   ` Ben Whitten
2018-07-15 18:13   ` Andreas Färber
2018-07-15 18:13     ` Andreas Färber
2018-07-15 18:13     ` Andreas Färber
2018-07-18 11:28     ` Ben Whitten
2018-07-18 11:28       ` Ben Whitten
2018-07-18 11:28       ` Ben Whitten
2018-07-18 11:28       ` Ben Whitten
2018-08-02  7:52       ` Jian-Hong Pan
2018-08-02  7:52         ` Jian-Hong Pan
2018-08-02  7:52         ` Jian-Hong Pan
2018-08-02  7:52         ` Jian-Hong Pan
2018-08-03  8:44         ` linux-lora.git and LoRaWAN (was: [RFC net-next 00/15] net: A socket API for LoRa) Andreas Färber
2018-08-03  8:44           ` Andreas Färber
2018-08-05 12:49           ` Jian-Hong Pan
2018-08-05 12:49             ` Jian-Hong Pan
2018-08-05 12:49             ` Jian-Hong Pan
2018-08-05 12:49             ` Jian-Hong Pan
     [not found]           ` <20180803150258.791b9942@alans-desktop>
2018-08-05 14:08             ` Jian-Hong Pan
2018-08-05 14:08               ` Jian-Hong Pan
2018-08-05 13:49       ` [RFC net-next 00/15] net: A socket API for LoRa Andreas Färber
2018-08-05 13:49         ` Andreas Färber
2018-08-05 13:49         ` Andreas Färber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180701110804.32415-11-afaerber@suse.de \
    --to=afaerber@suse.de \
    --cc=davem@davemloft.net \
    --cc=dollar.chen@wtmec.com \
    --cc=jiri@resnulli.us \
    --cc=jpiwek@arroweurope.com \
    --cc=ken.yu@rakwireless.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marcel@holtmann.org \
    --cc=mbrugger@suse.com \
    --cc=michael.roeder@avnet.eu \
    --cc=netdev@vger.kernel.org \
    --cc=starnight@g.ncu.edu.tw \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.