From patchwork Sun Jul 1 11:07:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937547 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="DliU/Z0X"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSNh1wsCz9s2g for ; Sun, 1 Jul 2018 21:10:44 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=6iPuXqNt/Xeq9LX4WfvSFlIx9Sx8+HPgSYuaspRVxNk=; b=DliU/Z0XjOzfx+ zeYdYtD91kJSuGYt1Frjq49hp6N7d/Alq3ampfTYzdH2m+q+mtTpSB4G9P/VcnqPhEPT0IbeQIGQU 6c9p5EtKUifwbP2+sYZB9pgnbD2+gueNsrrSt4dM3wvq07jxY0wE0/vhed6BnQkQ+oOWFcdj3rY91 prxCzH43bIMcV9WVFvTdBKwToWuAXpoWYtJucALtIKlpmrmQqsG0lrrPpT78UoFnHuh03GIoaPJiE hwPZbVviQ6XseDzAT9CE5ujcKw9lJZyjQ5UYG396pbipOclwfwgJyqnVUDLW8xwsjBpPW0Yfs43IS l/0Z8fIy2QMx4q8N31wQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaFV-0005bF-FS; Sun, 01 Jul 2018 11:10:33 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEC-0004Vm-BC for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:16 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 7BAEDAE53; Sun, 1 Jul 2018 11:08:57 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 01/15] net: Reserve protocol numbers for LoRa Date: Sun, 1 Jul 2018 13:07:50 +0200 Message-Id: <20180701110804.32415-2-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040912_802255_8CD4A507 X-CRM114-Status: GOOD ( 12.96 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Paul Moore , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Mich?= =?utf-8?q?ael_R=C3=B6der?= , Janus Piwek , selinux@tycho.nsa.gov, =?utf-8?q?Andreas_F=C3=A4rber?= , Eric Paris , Jian-Hong Pan , Ken Yu , Stephen Smalley , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org LoRa is a long-range, low-power wireless network technology by Semtech. It serves as base for LoRaWAN as well as multiple proprietary protocols. AF_LORA PF_LORA ARPHRD_LORA ETH_P_LORA Signed-off-by: Andreas Färber --- include/linux/socket.h | 4 +++- include/uapi/linux/if_arp.h | 1 + include/uapi/linux/if_ether.h | 1 + security/selinux/hooks.c | 4 +++- security/selinux/include/classmap.h | 4 +++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/include/linux/socket.h b/include/linux/socket.h index 7ed4713d5337..aa1e288b1659 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -208,8 +208,9 @@ struct ucred { * reuses AF_INET address family */ #define AF_XDP 44 /* XDP sockets */ +#define AF_LORA 45 /* LoRa sockets */ -#define AF_MAX 45 /* For now.. */ +#define AF_MAX 46 /* For now.. */ /* Protocol families, same as address families. */ #define PF_UNSPEC AF_UNSPEC @@ -259,6 +260,7 @@ struct ucred { #define PF_QIPCRTR AF_QIPCRTR #define PF_SMC AF_SMC #define PF_XDP AF_XDP +#define PF_LORA AF_LORA #define PF_MAX AF_MAX /* Maximum queue length specifiable by listen. */ diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h index 4605527ca41b..1ed7cb3f2129 100644 --- a/include/uapi/linux/if_arp.h +++ b/include/uapi/linux/if_arp.h @@ -98,6 +98,7 @@ #define ARPHRD_NETLINK 824 /* Netlink header */ #define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */ #define ARPHRD_VSOCKMON 826 /* Vsock monitor header */ +#define ARPHRD_LORA 827 /* LoRa */ #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index 3a45b4ad71a3..45644dcf5b39 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -147,6 +147,7 @@ #define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and * aggregation protocol */ +#define ETH_P_LORA 0x00FA /* LoRa */ /* * This is an Ethernet frame header. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 10a5d2ce3870..b62bb0389d70 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1473,7 +1473,9 @@ static inline u16 socket_type_to_security_class(int family, int type, int protoc return SECCLASS_SMC_SOCKET; case PF_XDP: return SECCLASS_XDP_SOCKET; -#if PF_MAX > 45 + case PF_LORA: + return SECCLASS_LORA_SOCKET; +#if PF_MAX > 46 #error New address family defined, please update this function. #endif } diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index bd5fe0d3204a..060d4bf8385e 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -242,9 +242,11 @@ struct security_class_mapping secclass_map[] = { {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, { "xdp_socket", { COMMON_SOCK_PERMS, NULL } }, + { "lora_socket", + { COMMON_SOCK_PERMS, NULL } }, { NULL } }; -#if PF_MAX > 45 +#if PF_MAX > 46 #error New address family defined, please update secclass_map. #endif From patchwork Sun Jul 1 11:07:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937538 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="iCTGz5f7"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSM756Flz9s2R for ; Sun, 1 Jul 2018 21:09:23 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=qRdeh6wBPf4UKuReac4UcCjz9dqxlXx+2kNfzzWi6cM=; b=iCTGz5f7rPEKGO ZQ35B/Il9hHsY9T82b9JZStY0H1PRcR30jefLeOglwhaajoyHWv8iNCvhmFAZFoKPvIEJdN9mVfi4 FY8TryLBNQrLVFHJyyaDXcG1Z6JbfaQj1zTaRkJqWE6D6WKyw52AWZ3Y3zJq0QIwdDq2cdnvCcyc5 5qVlQGj44P/nUX7MIgHpmDAazIBeLRSeb5mkC5gP/HQpLENBOedmWzwrbvCkgdUGr5SqStq0afqul ytDUKGk1vtZEDr12UHcSfsRKEml60XQcMw4OSke3C4wnq2MrdI+A2dMw0lR1b0kLa3Qi7UT8upNjI 6eFQ29x6ABk6hfuRF2/A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEH-0004Xg-7l; Sun, 01 Jul 2018 11:09:17 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEC-0004Vn-B7 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:14 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 78657AE0B; Sun, 1 Jul 2018 11:08:57 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 02/15] net: lora: Define sockaddr_lora Date: Sun, 1 Jul 2018 13:07:51 +0200 Message-Id: <20180701110804.32415-3-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040912_573632_3D4435A8 X-CRM114-Status: GOOD ( 10.39 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Prepare a uapi linux/lora.h header defining sockaddr_lora for AF_LORA. Signed-off-by: Andreas Färber --- include/uapi/linux/lora.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 include/uapi/linux/lora.h diff --git a/include/uapi/linux/lora.h b/include/uapi/linux/lora.h new file mode 100644 index 000000000000..9368e8a84f3a --- /dev/null +++ b/include/uapi/linux/lora.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: (GPL-2.0-or-later WITH Linux-syscall-note) */ +/* + * linux/lora.h + * + * Copyright (c) 2017-2018 Andreas Färber + */ +#ifndef _UAPI_LINUX_LORA_H +#define _UAPI_LINUX_LORA_H + +#include +#include + +struct sockaddr_lora { + __kernel_sa_family_t lora_family; + int lora_ifindex; + union { + } lora_addr; +}; + +#endif /* _UAPI_LINUX_LORA_H */ From patchwork Sun Jul 1 11:07:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937542 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="OAjl7jDG"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSND0ptPz9s1b for ; Sun, 1 Jul 2018 21:10:19 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=5cYheWait3ZgbaC5b/Rwf3K6H6kmd8a5ts5MEAsgYh0=; b=OAjl7jDGvQcrOb z9M425uBrzSXe61vmlEJAj9m2eqwI/hsYCNzkuLZWyvRwpyD0f7R0lZnQLjVWdtfP1HLFIymf7NTe /IqKfFYulC3GOhIFTmOKVHDLhDcZTAqLgnHYdBwfkLUjCkx3GkN5Vwi6ebtSIi9WYd4fXMsLB8Heb NMSQTQxioBbEIJQz9D9dEOe2tZSZO7IMe0JPbBOKV3XHaOujZYhPs+0oEvxZTQzjKjmCwT3vC6s/q Tyq9rF9r3n05Mh4Eljvc1zgRH+2c34yfIwPVj0qHfCSRbtc3yg53Rvd4W+XON89PtCMEaxIurTnSw 6j9lZS5sBgli5skWegdQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaF7-0005Av-98; Sun, 01 Jul 2018 11:10:09 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEC-0004Vk-B4 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:15 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 787A0AE3F; Sun, 1 Jul 2018 11:08:57 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 03/15] net: lora: Add protocol numbers Date: Sun, 1 Jul 2018 13:07:52 +0200 Message-Id: <20180701110804.32415-4-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040912_577170_E74ABFB9 X-CRM114-Status: UNSURE ( 8.77 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Default protocol implementation will be datagram. No other protocols are implemented yet. Q: Would these protocol numbers be the suitable place to define LoRaWAN? Signed-off-by: Andreas Färber --- include/uapi/linux/lora.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/uapi/linux/lora.h b/include/uapi/linux/lora.h index 9368e8a84f3a..4ff00b9c3c20 100644 --- a/include/uapi/linux/lora.h +++ b/include/uapi/linux/lora.h @@ -10,6 +10,10 @@ #include #include +/* particular protocols of the protocol family PF_LORA */ +#define LORA_PROTO_DATAGRAM 0 +#define LORA_NPROTO 1 + struct sockaddr_lora { __kernel_sa_family_t lora_family; int lora_ifindex; From patchwork Sun Jul 1 11:07:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937548 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="USJCvY0T"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSP667Yyz9s1b for ; Sun, 1 Jul 2018 21:11:06 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=grlMLlp7i/ebmheFu9ioDjCKsQ/UUR+7FYM/t6fpkA4=; b=USJCvY0TVrAiu5 vf+eBoW+vc9wlWmTUaeImvfb+Q0hQL9/kr6oF6jvOPu+8VBehyQrHmAg8lTbNOa7bmrE86gQnXRys A7wTFRL37HvBr38O6+/G1blREMHQaqURula4z0FJ7objnnRbBMsXxlUinAvLDbL8SOSt/Iztr38xf jrGT+LMOtEHSkmIZPDaNFXOBuCDjsqgy2rH4KBuToXWuUx6cxJS9ijJ1JSFidd79gFVX7nvcZ+v0N rDs3IpDmClgzWU53UcHr5HPpSQaAl0frxXG+dJEHKqhpRsSBDo13eLHYoqr+usiYrmoyDK4e93yZ0 HLg3LXJcTxh/m75+vLSA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaFv-00063w-6z; Sun, 01 Jul 2018 11:10:59 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEC-0004Vj-B5 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:19 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 7E356AE54; Sun, 1 Jul 2018 11:08:57 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 04/15] net: Add lora subsystem Date: Sun, 1 Jul 2018 13:07:53 +0200 Message-Id: <20180701110804.32415-5-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040912_809100_4E50B4BE X-CRM114-Status: GOOD ( 18.83 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Implement or stub out PF_LORA net_proto_family and datagram proto_ops. Signed-off-by: Andreas Färber --- include/linux/lora/skb.h | 29 +++++ net/Kconfig | 1 + net/Makefile | 1 + net/lora/Kconfig | 9 ++ net/lora/Makefile | 8 ++ net/lora/af_lora.c | 152 ++++++++++++++++++++++++ net/lora/af_lora.h | 13 +++ net/lora/dgram.c | 293 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 506 insertions(+) create mode 100644 include/linux/lora/skb.h create mode 100644 net/lora/Kconfig create mode 100644 net/lora/Makefile create mode 100644 net/lora/af_lora.c create mode 100644 net/lora/af_lora.h create mode 100644 net/lora/dgram.c diff --git a/include/linux/lora/skb.h b/include/linux/lora/skb.h new file mode 100644 index 000000000000..8806741464d0 --- /dev/null +++ b/include/linux/lora/skb.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/lora/skb.h + * + * Copyright (c) 2017-2018 Andreas Färber + */ +#ifndef _LORA_SKB_H +#define _LORA_SKB_H + +#include +#include + +struct lora_skb_priv { + int ifindex; +}; + +static inline struct lora_skb_priv *lora_skb_prv(struct sk_buff *skb) +{ + return (struct lora_skb_priv *)(skb->head); +} + +static inline void lora_skb_reserve(struct sk_buff *skb) +{ + skb_reserve(skb, sizeof(struct lora_skb_priv)); +} + +struct sk_buff *alloc_lora_skb(struct net_device *dev, u8 **data); + +#endif /* _LORA_SKB_H */ diff --git a/net/Kconfig b/net/Kconfig index f738a6f27665..d294ecc50a3b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -223,6 +223,7 @@ source "net/phonet/Kconfig" source "net/6lowpan/Kconfig" source "net/ieee802154/Kconfig" source "net/mac802154/Kconfig" +source "net/lora/Kconfig" source "net/sched/Kconfig" source "net/dcb/Kconfig" source "net/dns_resolver/Kconfig" diff --git a/net/Makefile b/net/Makefile index bdaf53925acd..e80b84313851 100644 --- a/net/Makefile +++ b/net/Makefile @@ -62,6 +62,7 @@ endif obj-$(CONFIG_6LOWPAN) += 6lowpan/ obj-$(CONFIG_IEEE802154) += ieee802154/ obj-$(CONFIG_MAC802154) += mac802154/ +obj-$(CONFIG_LORA) += lora/ ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o diff --git a/net/lora/Kconfig b/net/lora/Kconfig new file mode 100644 index 000000000000..44972ea8769f --- /dev/null +++ b/net/lora/Kconfig @@ -0,0 +1,9 @@ +# +# LoRa +# + +menuconfig LORA + depends on NET + tristate "LoRa subsystem support" + help + LoRa ... diff --git a/net/lora/Makefile b/net/lora/Makefile new file mode 100644 index 000000000000..b58675ef7846 --- /dev/null +++ b/net/lora/Makefile @@ -0,0 +1,8 @@ +# +# LoRa +# + +obj-$(CONFIG_LORA) += lora.o + +lora-y := af_lora.o +lora-y += dgram.o diff --git a/net/lora/af_lora.c b/net/lora/af_lora.c new file mode 100644 index 000000000000..662482fe4c9b --- /dev/null +++ b/net/lora/af_lora.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include + +#include "af_lora.h" + +int lora_send(struct sk_buff *skb) +{ + int ret; + + pr_debug("lora: %s\n", __func__); + + skb->protocol = htons(ETH_P_LORA); + + if (unlikely(skb->len > skb->dev->mtu)) { + ret = -EMSGSIZE; + goto err_skb; + } + + if (unlikely(skb->dev->type != ARPHRD_LORA)) { + ret = -EPERM; + goto err_skb; + } + + if (unlikely(!(skb->dev->flags & IFF_UP))) { + ret = -ENETDOWN; + goto err_skb; + } + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + + if (false) { + skb->pkt_type = PACKET_LOOPBACK; + } else + skb->pkt_type = PACKET_HOST; + + ret = dev_queue_xmit(skb); + if (ret > 0) + ret = net_xmit_errno(ret); + if (ret) + return ret; + + return 0; + +err_skb: + kfree_skb(skb); + return ret; +} +EXPORT_SYMBOL(lora_send); + +static void lora_sock_destruct(struct sock *sk) +{ + pr_debug("lora: %s\n", __func__); + + skb_queue_purge(&sk->sk_receive_queue); +} + +static int lora_create(struct net *net, struct socket *sock, int protocol, + int kern) +{ + struct sock *sk; + + pr_debug("lora: %s\n", __func__); + + sock->state = SS_UNCONNECTED; + + if (protocol < 0 || protocol > LORA_NPROTO) + return -EINVAL; + + /*if (!net_eq(net, &init_net)) + return -EAFNOSUPPORT;*/ + + if (sock->type != SOCK_DGRAM) + return -ESOCKTNOSUPPORT; + + sock->ops = &dgram_proto_ops; + + sk = sk_alloc(net, PF_LORA, GFP_KERNEL, &dgram_proto, kern); + if (!sk) + return -ENOMEM; + + sock_init_data(sock, sk); + sk->sk_family = PF_LORA; + sk->sk_destruct = lora_sock_destruct; + + if (sk->sk_prot->init) { + int ret = sk->sk_prot->init(sk); + if (ret) { + sock_orphan(sk); + sock_put(sk); + return ret; + } + } + + return 0; +} + +static const struct net_proto_family lora_net_proto_family = { + .family = PF_LORA, + .owner = THIS_MODULE, + .create = lora_create, +}; + +static __init int lora_init(void) +{ + int ret; + + pr_debug("lora: init\n"); + + ret = proto_register(&dgram_proto, 1); + if (ret) + goto err_dgram; + + ret = sock_register(&lora_net_proto_family); + if (ret) + goto err_sock; + + return 0; + +err_sock: + proto_unregister(&dgram_proto); +err_dgram: + return ret; +} + +static __exit void lora_exit(void) +{ + pr_debug("lora: exit\n"); + + sock_unregister(PF_LORA); + proto_unregister(&dgram_proto); +} + +module_init(lora_init); +module_exit(lora_exit); + +MODULE_DESCRIPTION("LoRa PF_LORA core"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_LORA); diff --git a/net/lora/af_lora.h b/net/lora/af_lora.h new file mode 100644 index 000000000000..47dd863531b2 --- /dev/null +++ b/net/lora/af_lora.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2017-2018 Andreas Färber + */ +#ifndef AF_LORA_H +#define AF_LORA_H + +extern struct proto dgram_proto; +extern const struct proto_ops dgram_proto_ops; + +int lora_send(struct sk_buff *skb); + +#endif /* AF_LORA_H */ diff --git a/net/lora/dgram.c b/net/lora/dgram.c new file mode 100644 index 000000000000..4d931fd3778a --- /dev/null +++ b/net/lora/dgram.c @@ -0,0 +1,293 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "af_lora.h" + +struct dgram_sock { + struct sock sk; + int ifindex; + bool bound; + struct notifier_block notifier; +}; + +static inline struct dgram_sock *dgram_sk(const struct sock *sk) +{ + return (struct dgram_sock *)sk; +} + +static int dgram_bind(struct socket *sock, struct sockaddr *uaddr, int len) +{ + struct sockaddr_lora *addr = (struct sockaddr_lora *)uaddr; + struct sock *sk = sock->sk; + struct dgram_sock *dgram = dgram_sk(sk); + int ifindex; + int ret = 0; + bool notify_enetdown = false; + + pr_debug("lora: %s\n", __func__); + + if (len < sizeof(*addr)) + return -EINVAL; + + lock_sock(sk); + + if (dgram->bound && addr->lora_ifindex == dgram->ifindex) + goto out; + + if (addr->lora_ifindex) { + struct net_device *netdev; + + netdev = dev_get_by_index(sock_net(sk), addr->lora_ifindex); + if (!netdev) { + ret = -ENODEV; + goto out; + } + if (netdev->type != ARPHRD_LORA) { + dev_put(netdev); + ret = -ENODEV; + goto out; + } + if (!(netdev->flags & IFF_UP)) + notify_enetdown = true; + + ifindex = netdev->ifindex; + + dev_put(netdev); + } else + ifindex = 0; + + dgram->ifindex = ifindex; + dgram->bound = true; + +out: + release_sock(sk); + + if (notify_enetdown) { + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + } + + return ret; +} + +static int dgram_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) +{ + struct sock *sk = sock->sk; + struct dgram_sock *dgram = dgram_sk(sk); + struct sk_buff *skb; + struct net_device *netdev; + int ifindex; + int ret; + + pr_debug("lora: %s\n", __func__); + + if (msg->msg_name) { + DECLARE_SOCKADDR(struct sockaddr_lora *, addr, msg->msg_name); + + if (msg->msg_namelen < sizeof(*addr)) + return -EINVAL; + + if (addr->lora_family != AF_LORA) + return -EINVAL; + + ifindex = addr->lora_ifindex; + } else + ifindex = dgram->ifindex; + + netdev = dev_get_by_index(sock_net(sk), ifindex); + if (!netdev) + return -ENXIO; + + skb = sock_alloc_send_skb(sk, size + sizeof(struct lora_skb_priv), + msg->msg_flags & MSG_DONTWAIT, &ret); + if (!skb) + goto err_sock_alloc_send_skb; + + lora_skb_reserve(skb); + lora_skb_prv(skb)->ifindex = netdev->ifindex; + + ret = memcpy_from_msg(skb_put(skb, size), msg, size); + if (ret < 0) + goto err_memcpy_from_msg; + + sock_tx_timestamp(sk, + sk->sk_tsflags, + &skb_shinfo(skb)->tx_flags); + + skb->dev = netdev; + skb->sk = sk; + skb->priority = sk->sk_priority; + + ret = lora_send(skb); + + dev_put(netdev); + + if (ret) + return ret; + + return size; + +err_memcpy_from_msg: + kfree_skb(skb); +err_sock_alloc_send_skb: + dev_put(netdev); + return ret; +} + +static int dgram_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + pr_debug("lora: %s\n", __func__); + + return -ENOIOCTLCMD; +} + +static int dgram_getname(struct socket *sock, struct sockaddr *uaddr, +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0) + int *len, +#endif + int peer) +{ + struct sockaddr_lora *addr = (struct sockaddr_lora *)uaddr; + struct sock *sk = sock->sk; + struct dgram_sock *dgram = dgram_sk(sk); + + pr_debug("lora: %s\n", __func__); + + if (peer) + return -EOPNOTSUPP; + + memset(addr, 0, sizeof(*addr)); + addr->lora_family = AF_LORA; + addr->lora_ifindex = dgram->ifindex; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0) + return sizeof(*addr); +#else + *len = sizeof(*addr); + return 0; +#endif +} + +static int dgram_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + struct dgram_sock *dgram; + + pr_debug("lora: %s\n", __func__); + + if (!sk) + return 0; + + dgram = dgram_sk(sk); + + unregister_netdevice_notifier(&dgram->notifier); + + lock_sock(sk); + + dgram->ifindex = 0; + dgram->bound = false; + + sock_orphan(sk); + sock->sk = NULL; + + release_sock(sk); + sock_put(sk); + + return 0; +} + +const struct proto_ops dgram_proto_ops = { + .family = PF_LORA, + .release = dgram_release, + .bind = dgram_bind, + .connect = sock_no_connect, + .socketpair = sock_no_socketpair, + .accept = sock_no_accept, + .getname = dgram_getname, + .poll = datagram_poll, + .ioctl = dgram_ioctl, + .listen = sock_no_listen, + .shutdown = sock_no_shutdown, + .setsockopt = sock_no_setsockopt, + .getsockopt = sock_no_getsockopt, + .sendmsg = dgram_sendmsg, + .recvmsg = sock_no_recvmsg, + .mmap = sock_no_mmap, + .sendpage = sock_no_sendpage, +}; + +static int dgram_notifier(struct notifier_block *nb, unsigned long msg, void *ptr) +{ + struct net_device *netdev = netdev_notifier_info_to_dev(ptr); + struct dgram_sock *dgram = container_of(nb, struct dgram_sock, notifier); + struct sock *sk = &dgram->sk; + + pr_debug("lora: %s\n", __func__); + + if (!net_eq(dev_net(netdev), sock_net(sk))) + return NOTIFY_DONE; + + if (netdev->type != ARPHRD_LORA) + return NOTIFY_DONE; + + if (dgram->ifindex != netdev->ifindex) + return NOTIFY_DONE; + + switch (msg) { + case NETDEV_UNREGISTER: + lock_sock(sk); + + dgram->ifindex = 0; + dgram->bound = false; + + release_sock(sk); + + sk->sk_err = ENODEV; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + break; + + case NETDEV_DOWN: + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); + break; + } + + return NOTIFY_DONE; +} + +static int dgram_init(struct sock *sk) +{ + struct dgram_sock *dgram = dgram_sk(sk); + + pr_debug("lora: %s\n", __func__); + + dgram->bound = false; + dgram->ifindex = 0; + + dgram->notifier.notifier_call = dgram_notifier; + register_netdevice_notifier(&dgram->notifier); + + return 0; +} + +struct proto dgram_proto __read_mostly = { + .name = "LoRa", + .owner = THIS_MODULE, + .obj_size = sizeof(struct dgram_sock), + .init = dgram_init, +}; From patchwork Sun Jul 1 11:07:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937540 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="IcgtUTWQ"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSMT3mzBz9s2R for ; Sun, 1 Jul 2018 21:09:41 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=rWBCQcPhN05+WFxXnmN/Wd06cEtz6yu/O9ziUK9MVZA=; b=IcgtUTWQ6DWNYg NmuZyREolH2T3H42zWhW+6qPJe6T1cwnQ3Birq3XAc4thPdH8+WX24yw/BEzXCNch9G1zKMi1Fyc9 VvyDvroRxgok1+z4YhfAdB9dRvfVGUyBv5I8YCiJEvCZfU+8DWA8OaXNT1yzjyutsVRQPO41D4+b5 hoXbMf3YzdmnLhZFwb18dquj+DvO3ViBCFX2Rj9HnCJMm6PviT0hBLFwvG+vI2LLa0eX6ano1qBpb hqC8DyuLOyb85q2wnanBDErRgmKPkC8BSFBUPtG9JRV8Ii57kHkgcThCoYzF/kCpEfPuTW+5Ztp37 jVAmluiL0+LpVaFxP0NA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEb-0004nC-JD; Sun, 01 Jul 2018 11:09:37 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEC-0004Vl-BB for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:13 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 8B3BCAE55; Sun, 1 Jul 2018 11:08:57 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 05/15] HACK: net: lora: Deal with .poll_mask in 4.18-rc2 Date: Sun, 1 Jul 2018 13:07:54 +0200 Message-Id: <20180701110804.32415-6-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040912_569657_526DC21F X-CRM114-Status: UNSURE ( 9.02 ) X-CRM114-Notice: Please train this message. X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org linux-next and 4.18-rc2 both identify as LINUX_VERSION(4,18,0), but commit a11e1d432b51f63ba698d044441284a661f01144 (Revert changes to convert to ->poll_mask() and aio IOCB_CMD_POLL) reverted .poll_mask to .poll again. Signed-off-by: Andreas Färber --- net/lora/dgram.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/lora/dgram.c b/net/lora/dgram.c index 4d931fd3778a..ef56fd90e762 100644 --- a/net/lora/dgram.c +++ b/net/lora/dgram.c @@ -217,7 +217,11 @@ const struct proto_ops dgram_proto_ops = { .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = dgram_getname, +#if 0 /* LINUX_VERSION_CODE >= LINUX_VERSION(4, 18, 0) */ + .poll_mask = datagram_poll_mask, +#else .poll = datagram_poll, +#endif .ioctl = dgram_ioctl, .listen = sock_no_listen, .shutdown = sock_no_shutdown, From patchwork Sun Jul 1 11:07:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937551 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="iUklGCbn"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSPy3Vtkz9s2R for ; Sun, 1 Jul 2018 21:11:50 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=BfWKt+CbHydcYoCyP4AfjXcDIhOsiI/uSOJVd13hhvk=; b=iUklGCbnLuFvbR zjmhAW59TN/zgcn/7OoAMemLXgbkrrYSWBpd2Xb4Neto1BKZcsBN5F0ZUC+2keFK4zIFt+6fTRyAi i9hEJzoUYLuzKoP79E+wsFF6nTv7pTzbRSxA0/7cg2FJi4HWEa9fXjZhCybdSmWRkbojKT7qE5weC 19dmptJZLrTSnlHfK0PFoINWy3WfLppzwnEWkyseWc3Ql66KpuF+eMDANxicKccirabfqpvFec1bZ g+39BxZtUUvO7qjSXDrfgI9O7ShGFnBTZoHdRra3JBV63y1nW5fx+cPBPyWkqs/4kd5+qBvOpDXAL 8OLLWKI+p+ISciyCgJ+w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaGf-0006xT-7a; Sun, 01 Jul 2018 11:11:45 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004XU-8e for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:33 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 3DA29AE56; Sun, 1 Jul 2018 11:08:58 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 06/15] net: lora: Prepare for device drivers Date: Sun, 1 Jul 2018 13:07:55 +0200 Message-Id: <20180701110804.32415-7-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_076214_CBD0ED23 X-CRM114-Status: GOOD ( 14.00 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Implement helper functions for use by LoRa device drivers. Signed-off-by: Andreas Färber --- drivers/net/Makefile | 1 + drivers/net/lora/Kconfig | 18 +++++++ drivers/net/lora/Makefile | 10 ++++ drivers/net/lora/dev.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/lora/dev.h | 23 +++++++++ net/lora/Kconfig | 6 +++ 6 files changed, 183 insertions(+) create mode 100644 drivers/net/lora/Kconfig create mode 100644 drivers/net/lora/Makefile create mode 100644 drivers/net/lora/dev.c create mode 100644 include/linux/lora/dev.h diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 21cde7e78621..9819bf28633d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_ETHERNET) += ethernet/ obj-$(CONFIG_FDDI) += fddi/ obj-$(CONFIG_HIPPI) += hippi/ obj-$(CONFIG_HAMRADIO) += hamradio/ +obj-$(CONFIG_LORA) += lora/ obj-$(CONFIG_PLIP) += plip/ obj-$(CONFIG_PPP) += ppp/ obj-$(CONFIG_PPP_ASYNC) += ppp/ diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig new file mode 100644 index 000000000000..40969b148a50 --- /dev/null +++ b/drivers/net/lora/Kconfig @@ -0,0 +1,18 @@ +# +# LoRa +# + +menu "LoRa Device Drivers" + +config LORA_DEV + tristate "LoRa drivers" + default y + help + LoRa ... + If unsure, say Y. + +# +# Alphabetically sorted. +# + +endmenu diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile new file mode 100644 index 000000000000..8f9d25ea4e70 --- /dev/null +++ b/drivers/net/lora/Makefile @@ -0,0 +1,10 @@ +# +# LoRa +# + +obj-$(CONFIG_LORA_DEV) += lora-dev.o +lora-dev-y := dev.o + +# +# Alphabetically sorted. +# diff --git a/drivers/net/lora/dev.c b/drivers/net/lora/dev.c new file mode 100644 index 000000000000..8c01106008be --- /dev/null +++ b/drivers/net/lora/dev.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include + +#define LORA_MTU 256 /* XXX */ + +struct sk_buff *alloc_lora_skb(struct net_device *dev, u8 **data) +{ + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, sizeof(struct lora_skb_priv) + LORA_MTU); + if (unlikely(!skb)) + return NULL; + + skb->protocol = htons(ETH_P_LORA); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb_reset_mac_header(skb); + skb_reset_network_header(skb); + skb_reset_transport_header(skb); + + lora_skb_reserve(skb); + lora_skb_prv(skb)->ifindex = dev->ifindex; + + return skb; +} +EXPORT_SYMBOL_GPL(alloc_lora_skb); + +int open_loradev(struct net_device *dev) +{ + if (!netif_carrier_ok(dev)) + netif_carrier_on(dev); + + return 0; +} +EXPORT_SYMBOL_GPL(open_loradev); + +void close_loradev(struct net_device *dev) +{ +} +EXPORT_SYMBOL_GPL(close_loradev); + +static void lora_setup(struct net_device *dev) +{ + dev->type = ARPHRD_LORA; + dev->mtu = LORA_MTU; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 10; + + dev->flags = IFF_NOARP; + dev->features = 0; +} + +struct net_device *alloc_loradev(int sizeof_priv) +{ + struct net_device *dev; + struct lora_priv *priv; + + dev = alloc_netdev(sizeof_priv, "lora%d", NET_NAME_UNKNOWN, lora_setup); + if (!dev) + return NULL; + + priv = netdev_priv(dev); + priv->dev = dev; + + return dev; +} +EXPORT_SYMBOL_GPL(alloc_loradev); + +void free_loradev(struct net_device *dev) +{ + free_netdev(dev); +} +EXPORT_SYMBOL_GPL(free_loradev); + +static struct rtnl_link_ops lora_link_ops __read_mostly = { + .kind = "lora", + .setup = lora_setup, +}; + +int register_loradev(struct net_device *dev) +{ + dev->rtnl_link_ops = &lora_link_ops; + return register_netdev(dev); +} +EXPORT_SYMBOL_GPL(register_loradev); + +void unregister_loradev(struct net_device *dev) +{ + unregister_netdev(dev); +} +EXPORT_SYMBOL_GPL(unregister_loradev); + +static int __init lora_dev_init(void) +{ + printk("lora-dev: init\n"); + + return rtnl_link_register(&lora_link_ops); +} + +static void __exit lora_dev_exit(void) +{ + printk("lora-dev: exit\n"); + + rtnl_link_unregister(&lora_link_ops); +} + +module_init(lora_dev_init); +module_exit(lora_dev_exit); + +MODULE_DESCRIPTION("LoRa device driver interface"); +MODULE_ALIAS_RTNL_LINK("lora"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andreas Färber"); diff --git a/include/linux/lora/dev.h b/include/linux/lora/dev.h new file mode 100644 index 000000000000..531e68f0c9a6 --- /dev/null +++ b/include/linux/lora/dev.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * linux/lora/dev.h + * + * Copyright (c) 2017-2018 Andreas Färber + */ +#ifndef _LORA_DEV_H +#define _LORA_DEV_H + +#include + +struct net_device *alloc_loradev(int sizeof_priv); +void free_loradev(struct net_device *dev); +int register_loradev(struct net_device *dev); +void unregister_loradev(struct net_device *dev); +int open_loradev(struct net_device *dev); +void close_loradev(struct net_device *dev); + +struct lora_priv { + struct net_device *dev; +}; + +#endif /* _LORA_DEV_H */ diff --git a/net/lora/Kconfig b/net/lora/Kconfig index 44972ea8769f..20658fea3c7c 100644 --- a/net/lora/Kconfig +++ b/net/lora/Kconfig @@ -7,3 +7,9 @@ menuconfig LORA tristate "LoRa subsystem support" help LoRa ... + +if LORA + +source "drivers/net/lora/Kconfig" + +endif From patchwork Sun Jul 1 11:07:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937557 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="bCb+xPrl"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSR306djz9s1b for ; Sun, 1 Jul 2018 21:12:47 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=cygT9pgUviePxbN8Zcr6v693XMF9LX1fGlgZNET9x7w=; b=bCb+xPrlL9pf1B as3CZaGgtv2dbILguCaeWUCXfbhLQ0nbgKAzqYBcWxAVeGuuOzMdhn9XAZQsN2sHpBlKNr6SFk5vs ptBdMLOm/8tPTE5sXEjtFcD1ly2DQjLQpG9uiS14JJUl/wCPkT4mxLzgARaAPqj92H5vbmcNvSCcT tzPSj4vr+KRJsNyu5mKnLYqgr4lxNaFDcGJ3kdeH9qYPz/ViUppaDpnQ3p7OVolAFZp4J3NZi36z3 2LTif3I32MCM6NCDnkG75aRoEzgnVNoAN29wvjBLANQjz2D0b+um6cgMd605Rw2AYggpP3XWgzusC +UK9ZjnaSXxXzCJav/Lw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaHW-00087m-JP; Sun, 01 Jul 2018 11:12:38 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004XT-8c for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:48 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 0856BAEC9; Sun, 1 Jul 2018 11:08:59 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 07/15] net: lora: Add Semtech SX1276 Date: Sun, 1 Jul 2018 13:07:56 +0200 Message-Id: <20180701110804.32415-8-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_094952_8380B5CB X-CRM114-Status: GOOD ( 18.30 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Semtech SX1276/77/78/79 and SX1272/73 are LoRa transceivers with a SPI interface. They also offer a non-LoRa mode (not exposed here). Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 11 + drivers/net/lora/Makefile | 3 + drivers/net/lora/sx1276.c | 608 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 622 insertions(+) create mode 100644 drivers/net/lora/sx1276.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 40969b148a50..0436f6b09a1c 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -15,4 +15,15 @@ config LORA_DEV # Alphabetically sorted. # +if LORA_DEV + +config LORA_SX1276 + tristate "Semtech SX127x SPI driver" + default y + depends on SPI + help + Semtech SX1272/1276/1278 + +endif + endmenu diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index 8f9d25ea4e70..8845542dba50 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -8,3 +8,6 @@ lora-dev-y := dev.o # # Alphabetically sorted. # + +obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o +lora-sx1276-y := sx1276.o diff --git a/drivers/net/lora/sx1276.c b/drivers/net/lora/sx1276.c new file mode 100644 index 000000000000..d6732111247a --- /dev/null +++ b/drivers/net/lora/sx1276.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Semtech SX1272/SX1276 LoRa transceiver + * + * Copyright (c) 2016-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_FIFO 0x00 +#define REG_OPMODE 0x01 +#define REG_FRF_MSB 0x06 +#define REG_FRF_MID 0x07 +#define REG_FRF_LSB 0x08 +#define REG_PA_CONFIG 0x09 +#define LORA_REG_FIFO_ADDR_PTR 0x0d +#define LORA_REG_FIFO_TX_BASE_ADDR 0x0e +#define LORA_REG_IRQ_FLAGS_MASK 0x11 +#define LORA_REG_IRQ_FLAGS 0x12 +#define LORA_REG_PAYLOAD_LENGTH 0x22 +#define LORA_REG_SYNC_WORD 0x39 +#define REG_DIO_MAPPING1 0x40 +#define REG_DIO_MAPPING2 0x41 +#define REG_VERSION 0x42 +#define REG_PA_DAC 0x4d + +#define REG_OPMODE_LONG_RANGE_MODE BIT(7) +#define REG_OPMODE_LOW_FREQUENCY_MODE_ON BIT(3) +#define REG_OPMODE_MODE_MASK GENMASK(2, 0) +#define REG_OPMODE_MODE_SLEEP (0x0 << 0) +#define REG_OPMODE_MODE_STDBY (0x1 << 0) +#define REG_OPMODE_MODE_TX (0x3 << 0) +#define REG_OPMODE_MODE_RXCONTINUOUS (0x5 << 0) +#define REG_OPMODE_MODE_RXSINGLE (0x6 << 0) + +#define REG_PA_CONFIG_PA_SELECT BIT(7) + +#define LORA_REG_IRQ_FLAGS_TX_DONE BIT(3) + +#define REG_DIO_MAPPING1_DIO0_MASK GENMASK(7, 6) + +struct sx1276_priv { + struct lora_priv lora; + struct spi_device *spi; + + size_t fifosize; + int dio_gpio[6]; + + struct mutex spi_lock; + + struct sk_buff *tx_skb; + int tx_len; + + struct workqueue_struct *wq; + struct work_struct tx_work; +}; + +static int sx1276_read_single(struct spi_device *spi, u8 reg, u8 *val) +{ + u8 addr = reg & 0x7f; + return spi_write_then_read(spi, &addr, 1, val, 1); +} + +static int sx1276_write_single(struct spi_device *spi, u8 reg, u8 val) +{ + u8 buf[2]; + + buf[0] = reg | BIT(7); + buf[1] = val; + return spi_write(spi, buf, 2); +} + +static int sx1276_write_burst(struct spi_device *spi, u8 reg, size_t len, void *val) +{ + u8 buf = reg | BIT(7); + struct spi_transfer xfers[2] = { + [0] = { + .tx_buf = &buf, + .len = 1, + }, + [1] = { + .tx_buf = val, + .len = len, + }, + }; + + return spi_sync_transfer(spi, xfers, 2); +} + +static int sx1276_write_fifo(struct spi_device *spi, size_t len, void *val) +{ + return sx1276_write_burst(spi, REG_FIFO, len, val); +} + +static netdev_tx_t sx1276_loradev_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct sx1276_priv *priv = netdev_priv(netdev); + + netdev_dbg(netdev, "%s\n", __func__); + + if (priv->tx_skb || priv->tx_len) { + netdev_warn(netdev, "TX busy\n"); + return NETDEV_TX_BUSY; + } + + if (skb->protocol != htons(ETH_P_LORA)) { + kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + netif_stop_queue(netdev); + priv->tx_skb = skb; + queue_work(priv->wq, &priv->tx_work); + + return NETDEV_TX_OK; +} + +static int sx1276_tx(struct spi_device *spi, void *data, int data_len) +{ + u8 addr, val; + int ret; + + dev_dbg(&spi->dev, "%s\n", __func__); + + ret = sx1276_read_single(spi, REG_OPMODE, &val); + if (ret) { + dev_err(&spi->dev, "Failed to read RegOpMode (%d)\n", ret); + return ret; + } + dev_dbg(&spi->dev, "RegOpMode = 0x%02x\n", val); + if (!(val & REG_OPMODE_LONG_RANGE_MODE)) + dev_err(&spi->dev, "LongRange Mode not active!\n"); + if ((val & REG_OPMODE_MODE_MASK) == REG_OPMODE_MODE_SLEEP) + dev_err(&spi->dev, "Cannot access FIFO in Sleep Mode!\n"); + + ret = sx1276_read_single(spi, LORA_REG_FIFO_TX_BASE_ADDR, &addr); + if (ret) { + dev_err(&spi->dev, "Failed to read RegFifoTxBaseAddr (%d)\n", ret); + return ret; + } + dev_dbg(&spi->dev, "RegFifoTxBaseAddr = 0x%02x\n", addr); + + ret = sx1276_write_single(spi, LORA_REG_FIFO_ADDR_PTR, addr); + if (ret) { + dev_err(&spi->dev, "Failed to write RegFifoAddrPtr (%d)\n", ret); + return ret; + } + + ret = sx1276_write_single(spi, LORA_REG_PAYLOAD_LENGTH, data_len); + if (ret) { + dev_err(&spi->dev, "Failed to write RegPayloadLength (%d)\n", ret); + return ret; + } + + ret = sx1276_write_fifo(spi, data_len, data); + if (ret) { + dev_err(&spi->dev, "Failed to write into FIFO (%d)\n", ret); + return ret; + } + + ret = sx1276_read_single(spi, LORA_REG_IRQ_FLAGS, &val); + if (ret) { + dev_err(&spi->dev, "Failed to read RegIrqFlags (%d)\n", ret); + return ret; + } + dev_dbg(&spi->dev, "RegIrqFlags = 0x%02x\n", val); + + ret = sx1276_write_single(spi, LORA_REG_IRQ_FLAGS, LORA_REG_IRQ_FLAGS_TX_DONE); + if (ret) { + dev_err(&spi->dev, "Failed to write RegIrqFlags (%d)\n", ret); + return ret; + } + + ret = sx1276_read_single(spi, LORA_REG_IRQ_FLAGS_MASK, &val); + if (ret) { + dev_err(&spi->dev, "Failed to read RegIrqFlagsMask (%d)\n", ret); + return ret; + } + dev_dbg(&spi->dev, "RegIrqFlagsMask = 0x%02x\n", val); + + val &= ~LORA_REG_IRQ_FLAGS_TX_DONE; + ret = sx1276_write_single(spi, LORA_REG_IRQ_FLAGS_MASK, val); + if (ret) { + dev_err(&spi->dev, "Failed to write RegIrqFlagsMask (%d)\n", ret); + return ret; + } + + ret = sx1276_read_single(spi, REG_DIO_MAPPING1, &val); + if (ret) { + dev_err(&spi->dev, "Failed to read RegDioMapping1 (%d)\n", ret); + return ret; + } + + val &= ~REG_DIO_MAPPING1_DIO0_MASK; + val |= 0x1 << 6; + ret = sx1276_write_single(spi, REG_DIO_MAPPING1, val); + if (ret) { + dev_err(&spi->dev, "Failed to write RegDioMapping1 (%d)\n", ret); + return ret; + } + + ret = sx1276_read_single(spi, REG_OPMODE, &val); + if (ret) { + dev_err(&spi->dev, "Failed to read RegOpMode (%d)\n", ret); + return ret; + } + + val &= ~REG_OPMODE_MODE_MASK; + val |= REG_OPMODE_MODE_TX; + ret = sx1276_write_single(spi, REG_OPMODE, val); + if (ret) { + dev_err(&spi->dev, "Failed to write RegOpMode (%d)\n", ret); + return ret; + } + + dev_dbg(&spi->dev, "%s: done\n", __func__); + + return 0; +} + +static void sx1276_tx_work_handler(struct work_struct *ws) +{ + struct sx1276_priv *priv = container_of(ws, struct sx1276_priv, tx_work); + struct spi_device *spi = priv->spi; + struct net_device *netdev = spi_get_drvdata(spi); + + netdev_dbg(netdev, "%s\n", __func__); + + mutex_lock(&priv->spi_lock); + + if (priv->tx_skb) { + sx1276_tx(spi, priv->tx_skb->data, priv->tx_skb->data_len); + priv->tx_len = 1 + priv->tx_skb->data_len; + if (!(netdev->flags & IFF_ECHO) || + priv->tx_skb->pkt_type != PACKET_LOOPBACK || + priv->tx_skb->protocol != htons(ETH_P_LORA)) + kfree_skb(priv->tx_skb); + priv->tx_skb = NULL; + } + + mutex_unlock(&priv->spi_lock); +} + +static irqreturn_t sx1276_dio_interrupt(int irq, void *dev_id) +{ + struct net_device *netdev = dev_id; + struct sx1276_priv *priv = netdev_priv(netdev); + struct spi_device *spi = priv->spi; + u8 val; + int ret; + + netdev_dbg(netdev, "%s\n", __func__); + + mutex_lock(&priv->spi_lock); + + ret = sx1276_read_single(spi, LORA_REG_IRQ_FLAGS, &val); + if (ret) { + netdev_warn(netdev, "Failed to read RegIrqFlags (%d)\n", ret); + val = 0; + } + + if (val & LORA_REG_IRQ_FLAGS_TX_DONE) { + netdev_info(netdev, "TX done.\n"); + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += priv->tx_len - 1; + priv->tx_len = 0; + netif_wake_queue(netdev); + + ret = sx1276_write_single(spi, LORA_REG_IRQ_FLAGS, LORA_REG_IRQ_FLAGS_TX_DONE); + if (ret) + netdev_warn(netdev, "Failed to write RegIrqFlags (%d)\n", ret); + } + + mutex_unlock(&priv->spi_lock); + + return IRQ_HANDLED; +} + +static int sx1276_loradev_open(struct net_device *netdev) +{ + struct sx1276_priv *priv = netdev_priv(netdev); + struct spi_device *spi = to_spi_device(netdev->dev.parent); + u8 val; + int ret, irq; + + netdev_dbg(netdev, "%s\n", __func__); + + ret = open_loradev(netdev); + if (ret) + return ret; + + mutex_lock(&priv->spi_lock); + + ret = sx1276_read_single(spi, REG_OPMODE, &val); + if (ret) { + netdev_err(netdev, "Failed to read RegOpMode (%d)\n", ret); + goto err_opmode; + } + + val &= ~REG_OPMODE_MODE_MASK; + val |= REG_OPMODE_MODE_STDBY; + ret = sx1276_write_single(spi, REG_OPMODE, val); + if (ret) { + netdev_err(netdev, "Failed to write RegOpMode (%d)\n", ret); + goto err_opmode; + } + + priv->tx_skb = NULL; + priv->tx_len = 0; + + priv->wq = alloc_workqueue("sx1276_wq", WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + INIT_WORK(&priv->tx_work, sx1276_tx_work_handler); + + if (gpio_is_valid(priv->dio_gpio[0])) { + irq = gpio_to_irq(priv->dio_gpio[0]); + if (irq <= 0) + netdev_warn(netdev, "Failed to obtain interrupt for DIO0 (%d)\n", irq); + else { + netdev_info(netdev, "Succeeded in obtaining interrupt for DIO0: %d\n", irq); + ret = request_threaded_irq(irq, NULL, sx1276_dio_interrupt, IRQF_ONESHOT | IRQF_TRIGGER_RISING, netdev->name, netdev); + if (ret) { + netdev_err(netdev, "Failed to request interrupt for DIO0 (%d)\n", ret); + goto err_irq; + } + } + } + + netif_wake_queue(netdev); + + mutex_unlock(&priv->spi_lock); + + return 0; + +err_irq: + destroy_workqueue(priv->wq); + priv->wq = NULL; +err_opmode: + close_loradev(netdev); + mutex_unlock(&priv->spi_lock); + return ret; +} + +static int sx1276_loradev_stop(struct net_device *netdev) +{ + struct sx1276_priv *priv = netdev_priv(netdev); + struct spi_device *spi = to_spi_device(netdev->dev.parent); + u8 val; + int ret, irq; + + netdev_dbg(netdev, "%s\n", __func__); + + close_loradev(netdev); + + mutex_lock(&priv->spi_lock); + + ret = sx1276_write_single(spi, LORA_REG_IRQ_FLAGS_MASK, 0xff); + if (ret) { + netdev_err(netdev, "Failed to write RegIrqFlagsMask (%d)\n", ret); + goto err_irqmask; + } + + ret = sx1276_read_single(spi, REG_OPMODE, &val); + if (ret) { + netdev_err(netdev, "Failed to read RegOpMode (%d)\n", ret); + goto err_opmode; + } + + val &= ~REG_OPMODE_MODE_MASK; + val |= REG_OPMODE_MODE_SLEEP; + ret = sx1276_write_single(spi, REG_OPMODE, val); + if (ret) { + netdev_err(netdev, "Failed to write RegOpMode (%d)\n", ret); + goto err_opmode; + } + + if (gpio_is_valid(priv->dio_gpio[0])) { + irq = gpio_to_irq(priv->dio_gpio[0]); + if (irq > 0) { + netdev_dbg(netdev, "Freeing IRQ %d\n", irq); + free_irq(irq, netdev); + } + } + + destroy_workqueue(priv->wq); + priv->wq = NULL; + + if (priv->tx_skb || priv->tx_len) + netdev->stats.tx_errors++; + if (priv->tx_skb) + dev_kfree_skb(priv->tx_skb); + priv->tx_skb = NULL; + priv->tx_len = 0; + + mutex_unlock(&priv->spi_lock); + + return 0; + +err_opmode: +err_irqmask: + mutex_unlock(&priv->spi_lock); + return ret; +} + +static const struct net_device_ops sx1276_netdev_ops = { + .ndo_open = sx1276_loradev_open, + .ndo_stop = sx1276_loradev_stop, + .ndo_start_xmit = sx1276_loradev_start_xmit, +}; + +static int sx1276_probe(struct spi_device *spi) +{ + struct net_device *netdev; + struct sx1276_priv *priv; + int rst, dio[6], ret, model, i; + u32 freq_xosc, freq_band; + unsigned long long freq_rf; + u8 val; + + rst = of_get_named_gpio(spi->dev.of_node, "reset-gpio", 0); + if (rst == -ENOENT) + dev_warn(&spi->dev, "no reset GPIO available, ignoring"); + + for (i = 0; i < 6; i++) { + dio[i] = of_get_named_gpio(spi->dev.of_node, "dio-gpios", i); + if (dio[i] == -ENOENT) + dev_dbg(&spi->dev, "DIO%d not available, ignoring", i); + else { + ret = gpio_direction_input(dio[i]); + if (ret) + dev_err(&spi->dev, "couldn't set DIO%d to input", i); + } + } + + if (gpio_is_valid(rst)) { + gpio_set_value(rst, 1); + udelay(100); + gpio_set_value(rst, 0); + msleep(5); + } + + spi->bits_per_word = 8; + spi_setup(spi); + + ret = sx1276_read_single(spi, REG_VERSION, &val); + if (ret) { + dev_err(&spi->dev, "version read failed"); + return ret; + } + + if (val == 0x22) + model = 1272; + else { + if (gpio_is_valid(rst)) { + gpio_set_value(rst, 0); + udelay(100); + gpio_set_value(rst, 1); + msleep(5); + } + + ret = sx1276_read_single(spi, REG_VERSION, &val); + if (ret) { + dev_err(&spi->dev, "version read failed"); + return ret; + } + + if (val == 0x12) + model = 1276; + else { + dev_err(&spi->dev, "transceiver not recognized (RegVersion = 0x%02x)", (unsigned)val); + return -EINVAL; + } + } + + ret = of_property_read_u32(spi->dev.of_node, "clock-frequency", &freq_xosc); + if (ret) { + dev_err(&spi->dev, "failed reading clock-frequency"); + return ret; + } + + ret = of_property_read_u32(spi->dev.of_node, "radio-frequency", &freq_band); + if (ret) { + dev_err(&spi->dev, "failed reading radio-frequency"); + return ret; + } + + val = REG_OPMODE_LONG_RANGE_MODE | REG_OPMODE_MODE_SLEEP; + if (freq_band < 525000000) + val |= REG_OPMODE_LOW_FREQUENCY_MODE_ON; + ret = sx1276_write_single(spi, REG_OPMODE, val); + if (ret) { + dev_err(&spi->dev, "failed writing opmode"); + return ret; + } + + freq_rf = freq_band; + freq_rf *= (1 << 19); + freq_rf /= freq_xosc; + dev_dbg(&spi->dev, "Frf = %llu", freq_rf); + + ret = sx1276_write_single(spi, REG_FRF_MSB, freq_rf >> 16); + if (!ret) + ret = sx1276_write_single(spi, REG_FRF_MID, freq_rf >> 8); + if (!ret) + ret = sx1276_write_single(spi, REG_FRF_LSB, freq_rf); + if (ret) { + dev_err(&spi->dev, "failed writing frequency (%d)", ret); + return ret; + } + + ret = sx1276_read_single(spi, REG_PA_CONFIG, &val); + if (ret) { + dev_err(&spi->dev, "failed reading RegPaConfig\n"); + return ret; + } + if (true) + val |= REG_PA_CONFIG_PA_SELECT; + val &= ~GENMASK(3, 0); + val |= (23 - 3) - 5; + ret = sx1276_write_single(spi, REG_PA_CONFIG, val); + if (ret) { + dev_err(&spi->dev, "failed writing RegPaConfig\n"); + return ret; + } + + ret = sx1276_read_single(spi, REG_PA_DAC, &val); + if (ret) { + dev_err(&spi->dev, "failed reading RegPaDac\n"); + return ret; + } + val &= ~GENMASK(2, 0); + val |= 0x7; + ret = sx1276_write_single(spi, REG_PA_DAC, val); + if (ret) { + dev_err(&spi->dev, "failed writing RegPaDac\n"); + return ret; + } + + netdev = alloc_loradev(sizeof(struct sx1276_priv)); + if (!netdev) + return -ENOMEM; + + netdev->netdev_ops = &sx1276_netdev_ops; + netdev->flags |= IFF_ECHO; + + priv = netdev_priv(netdev); + priv->spi = spi; + mutex_init(&priv->spi_lock); + for (i = 0; i < 6; i++) + priv->dio_gpio[i] = dio[i]; + + spi_set_drvdata(spi, netdev); + SET_NETDEV_DEV(netdev, &spi->dev); + + ret = register_loradev(netdev); + if (ret) { + free_loradev(netdev); + return ret; + } + + dev_info(&spi->dev, "SX1276 module probed (SX%d)", model); + + return 0; +} + +static int sx1276_remove(struct spi_device *spi) +{ + struct net_device *netdev = spi_get_drvdata(spi); + + unregister_loradev(netdev); + free_loradev(netdev); + + dev_info(&spi->dev, "SX1276 module removed"); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id sx1276_dt_ids[] = { + { .compatible = "semtech,sx1272" }, + { .compatible = "semtech,sx1276" }, + {} +}; +MODULE_DEVICE_TABLE(of, sx1276_dt_ids); +#endif + +static struct spi_driver sx1276_spi_driver = { + .driver = { + .name = "sx1276", + .of_match_table = of_match_ptr(sx1276_dt_ids), + }, + .probe = sx1276_probe, + .remove = sx1276_remove, +}; + +module_spi_driver(sx1276_spi_driver); + +MODULE_DESCRIPTION("SX1276 SPI driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); From patchwork Sun Jul 1 11:07:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937555 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="DcSsWn5y"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSQW0LVMz9s2R for ; Sun, 1 Jul 2018 21:12:19 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=1tflAWTsif7nFst1fInS2uEh9n25xckdWN2IUPlwhKU=; b=DcSsWn5ySCKb7v wd+Vl5E9Bl5Ijd6hnFOb2SFOS1naIzQeBzX5iklSGmtw9A6IEKPmtPj1OGix45ZXsXJ5xbg7B4gWq zQGMes4l9KaJoGB56BuPv41d5zCJ4r+kZ2K/lflZtPmC3Cb1svTPL6aaYkw4NoesWgRdzVyDbZKQN 617C5MZ2r1J0KPAgwg7e1c0X7eU7BSjYUpd9aO+olBhtqWsakIqsY+IeLpsUGdzl5Q2c27iH8v9Lk TKWp1vMZte9dxs/N/NwGiv6jmQziA1fitheIxdg/19GQ2cDOqEDdqgXxxMqe4Qvc9S9gm8x0Fvht+ YUyKGCJ27iEX8jI1V8OA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaH8-0007ha-QE; Sun, 01 Jul 2018 11:12:14 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004XX-96 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:39 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 77AE8AF53; Sun, 1 Jul 2018 11:08:59 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 08/15] net: lora: sx1276: Add debugfs Date: Sun, 1 Jul 2018 13:07:57 +0200 Message-Id: <20180701110804.32415-9-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_591685_0FD7A575 X-CRM114-Status: GOOD ( 12.34 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org Allow some interactive inspection at runtime via debugfs. Signed-off-by: Andreas Färber --- drivers/net/lora/sx1276.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/drivers/net/lora/sx1276.c b/drivers/net/lora/sx1276.c index d6732111247a..1072019cfcc1 100644 --- a/drivers/net/lora/sx1276.c +++ b/drivers/net/lora/sx1276.c @@ -5,6 +5,7 @@ * Copyright (c) 2016-2018 Andreas Färber */ +#include #include #include #include @@ -61,6 +62,8 @@ struct sx1276_priv { struct workqueue_struct *wq; struct work_struct tx_work; + + struct dentry *debugfs; }; static int sx1276_read_single(struct spi_device *spi, u8 reg, u8 *val) @@ -416,6 +419,128 @@ static const struct net_device_ops sx1276_netdev_ops = { .ndo_start_xmit = sx1276_loradev_start_xmit, }; +static ssize_t sx1276_freq_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct net_device *netdev = file->private_data; + struct sx1276_priv *priv = netdev_priv(netdev); + struct spi_device *spi = priv->spi; + ssize_t size; + char *buf; + int ret; + u8 msb, mid, lsb; + u32 freq_xosc; + unsigned long long frf; + + ret = of_property_read_u32(spi->dev.of_node, "clock-frequency", &freq_xosc); + if (ret) + return 0; + + mutex_lock(&priv->spi_lock); + + ret = sx1276_read_single(spi, REG_FRF_MSB, &msb); + if (!ret) + ret = sx1276_read_single(spi, REG_FRF_MID, &mid); + if (!ret) + ret = sx1276_read_single(spi, REG_FRF_LSB, &lsb); + + mutex_unlock(&priv->spi_lock); + + if (ret) + return 0; + + frf = freq_xosc; + frf *= ((ulong)msb << 16) | ((ulong)mid << 8) | lsb; + frf /= (1 << 19); + + buf = kasprintf(GFP_KERNEL, "%llu\n", frf); + if (!buf) + return 0; + + size = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf)); + kfree(buf); + + return size; +} + +static const struct file_operations sx1276_freq_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = sx1276_freq_read, +}; + +static ssize_t sx1276_state_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct net_device *netdev = file->private_data; + struct sx1276_priv *priv = netdev_priv(netdev); + struct spi_device *spi = priv->spi; + ssize_t size; + char *buf; + int len = 0; + int ret; + u8 val; + bool lora_mode = true; + const int max_len = 4096; + + buf = kzalloc(max_len, GFP_KERNEL); + if (!buf) + return 0; + + mutex_lock(&priv->spi_lock); + + ret = sx1276_read_single(spi, REG_OPMODE, &val); + if (!ret) { + len += snprintf(buf + len, max_len - len, "RegOpMode = 0x%02x\n", val); + lora_mode = (val & REG_OPMODE_LONG_RANGE_MODE) != 0; + } + + ret = sx1276_read_single(spi, REG_FRF_MSB, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegFrMsb = 0x%02x\n", val); + ret = sx1276_read_single(spi, REG_FRF_MID, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegFrMid = 0x%02x\n", val); + ret = sx1276_read_single(spi, REG_FRF_LSB, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegFrLsb = 0x%02x\n", val); + + ret = sx1276_read_single(spi, REG_PA_CONFIG, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegPaConfig = 0x%02x\n", val); + + if (lora_mode) { + ret = sx1276_read_single(spi, LORA_REG_IRQ_FLAGS_MASK, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegIrqFlagsMask = 0x%02x\n", val); + + ret = sx1276_read_single(spi, LORA_REG_IRQ_FLAGS, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegIrqFlags = 0x%02x\n", val); + + ret = sx1276_read_single(spi, LORA_REG_SYNC_WORD, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegSyncWord = 0x%02x\n", val); + } + + ret = sx1276_read_single(spi, REG_PA_DAC, &val); + if (!ret) + len += snprintf(buf + len, max_len - len, "RegPaDac = 0x%02x\n", val); + + mutex_unlock(&priv->spi_lock); + + size = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return size; +} + +static const struct file_operations sx1276_state_fops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = sx1276_state_read, +}; + static int sx1276_probe(struct spi_device *spi) { struct net_device *netdev; @@ -566,6 +691,10 @@ static int sx1276_probe(struct spi_device *spi) return ret; } + priv->debugfs = debugfs_create_dir(dev_name(&spi->dev), NULL); + debugfs_create_file("state", S_IRUGO, priv->debugfs, netdev, &sx1276_state_fops); + debugfs_create_file("frequency", S_IRUGO, priv->debugfs, netdev, &sx1276_freq_fops); + dev_info(&spi->dev, "SX1276 module probed (SX%d)", model); return 0; @@ -574,6 +703,9 @@ static int sx1276_probe(struct spi_device *spi) static int sx1276_remove(struct spi_device *spi) { struct net_device *netdev = spi_get_drvdata(spi); + struct sx1276_priv *priv = netdev_priv(netdev); + + debugfs_remove_recursive(priv->debugfs); unregister_loradev(netdev); free_loradev(netdev); From patchwork Sun Jul 1 11:07:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937550 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="CQiLU3xC"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSPZ5fpYz9s1b for ; Sun, 1 Jul 2018 21:11:30 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=YIKl/wF74nPAPhpOSQTC2T16fjSB9CbPqHSqiRORToo=; b=CQiLU3xCyenrmq 2Bc9FIiZ1/gS1acwlEVrsEcvkzT3wDlsMMYbAKSJwcx23PVjwVG8Ai2saRqW5RS0JJau/EzIf4fen fXKbv++W1FC0wht6/P5GRlpSNKZ061FvThahGG8pePMjNt0sC1JOMU2WR2+8DSUP/9wLN27XWxyug T2LfrGNazvfX6B+HoDODiviXWTDWDMUygn91MYHW0XL0i6DXJ7DAq3SZ5q7I8FNb/PSSOGq9PnjSW bDxOY2HG9ChcjG1atiuxk7muML3OYclLclrQ7mPJYwjqPzxgVBgp5v9UokTo92QSxTfIcZ2O8QTog HtA4SmAHTNUJ/HNRKT6g==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaGH-0006VJ-Hj; Sun, 01 Jul 2018 11:11:21 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004XW-9R for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:30 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id EA72CAF54; Sun, 1 Jul 2018 11:08:59 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 09/15] net: lora: Prepare EUI helpers Date: Sun, 1 Jul 2018 13:07:58 +0200 Message-Id: <20180701110804.32415-10-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040925_908289_B0CBD302 X-CRM114-Status: GOOD ( 10.88 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org These will be used by the RN2483 and other LoRaWAN capable modules. Signed-off-by: Andreas Färber --- include/linux/lora/dev.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/linux/lora/dev.h b/include/linux/lora/dev.h index 531e68f0c9a6..153f9b2992ca 100644 --- a/include/linux/lora/dev.h +++ b/include/linux/lora/dev.h @@ -9,6 +9,27 @@ #include +typedef u8 lora_eui[8]; + +#define PRIxLORAEUI "%02x%02x%02x%02x%02x%02x%02x%02x" +#define PRIXLORAEUI "%02X%02X%02X%02X%02X%02X%02X%02X" +#define LORA_EUI(x) x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7] + +static inline int lora_strtoeui(const char *str, lora_eui *val) +{ + char buf[3]; + int i, ret; + + for (i = 0; i < 8; i++) { + strncpy(buf, str + i * 2, 2); + buf[2] = 0; + ret = kstrtou8(buf, 16, &(*val)[i]); + if (ret) + return ret; + } + return 0; +} + struct net_device *alloc_loradev(int sizeof_priv); void free_loradev(struct net_device *dev); int register_loradev(struct net_device *dev); From patchwork Sun Jul 1 11:07:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937568 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="D5fPdSm2"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSym18MGz9s29 for ; Sun, 1 Jul 2018 21:36:48 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Cl51hJYDouXJSObKkzi6UpOA4ohGdlyShGs8GFLxgLE=; b=D5fPdSm2tnZuji ZM+aZz1zUmrMf8HhQj2XJcirB9M/dhZfpIb7a+0OxnV6cKhudIS1+IDSZEsOSiJKNiRBlXsXOvWmj D1JbHnyJnRGVclKzHjgRI+fa7m6WwuOKSRIXfynibIMAeueQiosc7s9eD01jIGbW+wzjCzJ3mXY5L +pVuaBK+6gEwMWAWshRqIxYUresowH7QGDJwbRDBfcGQnvc5IFrp8zRNhVQOvz3jpixU8hp+6MRs9 K8/RXwYjk5dQY5vKG4UNdEnKfcpfha7Dllu2WjpVoV17/vUzHmr81sU12yzV27Dk2qNI8GVn7m2eN rqfwavaAda2slbqzP2oA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaep-0001l7-F1; Sun, 01 Jul 2018 11:36:43 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004Y0-95 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:10:01 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id C79AAAF62; Sun, 1 Jul 2018 11:09:00 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 10/15] net: lora: Add Microchip RN2483 Date: Sun, 1 Jul 2018 13:07:59 +0200 Message-Id: <20180701110804.32415-11-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_356201_747F43AC X-CRM114-Status: GOOD ( 19.34 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org 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 --- 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 +#include +#include +#include +#include +#include +#include +#include + +#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 "); +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 +#include +#include +#include +#include + +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; +} From patchwork Sun Jul 1 11:08:00 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937567 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="k8V/pfyD"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSyR3WCfz9s29 for ; Sun, 1 Jul 2018 21:36:31 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=D0qidOV7zPbWWoJ+A82rlBXlBAs1rGUhz9Dc4dCK7ok=; b=k8V/pfyDHTNawu +lFL9JF9VVtDbvb73AH1hjeZTbt39UqYxP2RgdIFBgpey2s0gl73jYX6vMFOvvJeYoKj5hB91oadV 8aW4ddrscNBL7/0rHzauH0YU+aM3jP4pQk9yZqMJOqUnUhZzttmtQ8ZM4HbcsSKAQY50Y0KaqgQaQ tmkbXrEzNZwi7ez7CJDZ6dhkKE5eSx4kzBQOjCr3pZvT9JPYTluc9buAiiMlgEvP0c/ytjq9hIg4G UikOs839TpfEiCQ9KIW7UgfBHbV+ctPT2iTsd8H5iA1Z+23VX7IURQgKfmbohIPum5Edb2E2HDd/2 dYFHz9ED/eXovSmLExNg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaeZ-0001Xk-O9; Sun, 01 Jul 2018 11:36:27 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004Y1-99 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:10:00 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 89CB7AFA3; Sun, 1 Jul 2018 11:09:01 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 11/15] net: lora: Add IMST WiMOD Date: Sun, 1 Jul 2018 13:08:00 +0200 Message-Id: <20180701110804.32415-12-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_195589_E85089A2 X-CRM114-Status: GOOD ( 20.07 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , Jon Ortego , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org The IMST WiMOD uses a SLIP based binary UART protocol. Two separate firmwares are available. By default it ships with a LoRaWAN firmware. The alternative firmware is a custom P2P addressing mode based on LoRa. Cc: Jon Ortego Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 8 + drivers/net/lora/Makefile | 3 + drivers/net/lora/wimod.c | 597 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 608 insertions(+) create mode 100644 drivers/net/lora/wimod.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 940bd2cbe106..2e05caef8645 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -31,6 +31,14 @@ config LORA_SX1276 help Semtech SX1272/1276/1278 +config LORA_WIMOD + tristate "IMST WiMOD driver" + default y + depends on SERIAL_DEV_BUS + select CRC_CCITT + help + IMST WiMOD + endif endmenu diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index 07839c3ce9f8..ecb326c859a5 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -15,3 +15,6 @@ lora-rn2483-y += rn2483_cmd.o obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o lora-sx1276-y := sx1276.o + +obj-$(CONFIG_LORA_WIMOD) += lora-wimod.o +lora-wimod-y := wimod.o diff --git a/drivers/net/lora/wimod.c b/drivers/net/lora/wimod.c new file mode 100644 index 000000000000..a70d5a6dc7c4 --- /dev/null +++ b/drivers/net/lora/wimod.c @@ -0,0 +1,597 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * IMST WiMOD + * + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include + +#define WIMOD_HCI_PAYLOAD_MAX 300 +#define WIMOD_HCI_PACKET_MAX (1 + (2 + WIMOD_HCI_PAYLOAD_MAX + 2) * 2 + 1) + +struct wimod_device { + struct serdev_device *serdev; + + u8 rx_buf[WIMOD_HCI_PACKET_MAX]; + int rx_len; + bool rx_esc; + struct list_head packet_dispatchers; +}; + +#define SLIP_END 0300 +#define SLIP_ESC 0333 +#define SLIP_ESC_END 0334 +#define SLIP_ESC_ESC 0335 + +static inline void slip_print_bytes(const u8* buf, int len) +{ + int i; + + for (i = 0; i < len; i++) + printk("%02x ", buf[i]); +} + +static int slip_send_end(struct serdev_device *sdev, unsigned long timeout) +{ + u8 val = SLIP_END; + + return serdev_device_write(sdev, &val, 1, timeout); +} + +#if 0 +static int slip_send_data(struct serdev_device *sdev, const u8 *buf, int len, + unsigned long timeout) +{ + int last_idx = -1; + int i; + u8 esc[2] = { SLIP_ESC, 0 }; + int ret; + + for (i = 0; i < len; i++) { + if (buf[i] != SLIP_END && + buf[i] != SLIP_ESC) + continue; + + slip_print_bytes(&buf[last_idx + 1], i - (last_idx + 1)); + + ret = serdev_device_write(sdev, + &buf[last_idx + 1], i - (last_idx + 1), timeout); + if (ret) + return ret; + + switch (buf[i]) { + case SLIP_END: + esc[1] = SLIP_ESC_END; + break; + case SLIP_ESC: + esc[1] = SLIP_ESC_ESC; + break; + } + slip_print_bytes(esc, 2); + ret = serdev_device_write(sdev, esc, 2, timeout); + if (ret) + return ret; + + last_idx = i; + } + + slip_print_bytes(&buf[last_idx + 1], len - (last_idx + 1)); + + ret = serdev_device_write(sdev, + &buf[last_idx + 1], len - (last_idx + 1), timeout); + + return ret; +} +#endif + +static int slip_write_data(u8 *buf, int buf_len, const u8 *data, int data_len) +{ + int last_idx = -1; + int i, n; + int count = 0; + + for (i = 0; i < data_len; i++) { + if (data[i] != SLIP_END && + data[i] != SLIP_ESC) + continue; + + n = i - (last_idx + 1); + if (count + n + 2 > buf_len) + return -ENOMEM; + + memcpy(buf + count, &data[last_idx + 1], n); + count += n; + + buf[count++] = SLIP_ESC; + switch (data[i]) { + case SLIP_END: + buf[count++] = SLIP_ESC_END; + break; + case SLIP_ESC: + buf[count++] = SLIP_ESC_ESC; + break; + } + + last_idx = i; + } + + n = data_len - (last_idx + 1); + if (count + n > buf_len) + return -ENOMEM; + + memcpy(buf + count, &data[last_idx + 1], n); + count += n; + + return count; +} + +#define DEVMGMT_ID 0x01 + +#define DEVMGMT_MSG_PING_REQ 0x01 +#define DEVMGMT_MSG_PING_RSP 0x02 +#define DEVMGMT_MSG_GET_DEVICE_INFO_REQ 0x03 +#define DEVMGMT_MSG_GET_DEVICE_INFO_RSP 0x04 +#define DEVMGMT_MSG_GET_FW_INFO_REQ 0x05 +#define DEVMGMT_MSG_GET_FW_INFO_RSP 0x06 + +#define DEVMGMT_STATUS_OK 0x00 + +struct wimod_hci_packet_dispatcher { + struct list_head list; + u8 dst_id; + u8 msg_id; + void (*dispatchee)(const u8*, int, struct wimod_hci_packet_dispatcher *); + void *priv; +}; + +struct wimod_hci_packet_completion { + struct wimod_hci_packet_dispatcher disp; + struct completion comp; + char *payload; + int payload_len; +}; + +static void wimod_hci_add_dispatcher(struct wimod_device *wmdev, + struct wimod_hci_packet_dispatcher *entry) +{ + list_add_tail_rcu(&entry->list, &wmdev->packet_dispatchers); +} + +static void wimod_hci_remove_dispatcher(struct wimod_device *wmdev, + struct wimod_hci_packet_dispatcher *entry) +{ + list_del_rcu(&entry->list); +} + +static void wimod_hci_packet_dispatch_completion(const u8 *data, int len, + struct wimod_hci_packet_dispatcher *d) +{ + struct wimod_hci_packet_completion *disp = + container_of(d, struct wimod_hci_packet_completion, disp); + + if (completion_done(&disp->comp)) + return; + + disp->payload_len = len - 2; + disp->payload = kzalloc(disp->payload_len, GFP_KERNEL); + if (disp->payload) + memcpy(disp->payload, data + 2, len - 2); + + complete(&disp->comp); +} + +static int wimod_hci_send(struct serdev_device *sdev, + u8 dst_id, u8 msg_id, const u8 *payload, int payload_len, + unsigned long timeout) +{ + u8 buf[WIMOD_HCI_PACKET_MAX]; + int buf_len = 0; + u16 crc = 0xffff; + int ret, i; + + if (payload_len > WIMOD_HCI_PAYLOAD_MAX) + return -EINVAL; + + for (i = 0; i < 30; i++) { + ret = slip_send_end(sdev, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: wakeup END %d failed\n", __func__, i); + return ret; + } + } + + crc = crc_ccitt_byte(crc, dst_id); + crc = crc_ccitt_byte(crc, msg_id); + if (payload_len > 0) + crc = crc_ccitt(crc, payload, payload_len); + crc = ~crc; + + printk(KERN_INFO "sending: "); + + /*ret = slip_send_end(sdev, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: initial END failed\n", __func__); + return ret; + } + + ret = slip_send_data(sdev, &dst_id, 1, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: dst_id failed\n", __func__); + return ret; + } + + ret = slip_send_data(sdev, &msg_id, 1, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: msg_id failed\n", __func__); + return ret; + }*/ + + buf[buf_len++] = SLIP_END; + + ret = slip_write_data(buf + buf_len, sizeof(buf) - buf_len, &dst_id, 1); + if (ret < 0) + return ret; + buf_len += ret; + + ret = slip_write_data(buf + buf_len, sizeof(buf) - buf_len, &msg_id, 1); + if (ret < 0) + return ret; + buf_len += ret; + + if (payload_len > 0) { + /*ret = slip_send_data(sdev, payload, payload_len, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: payload failed\n", __func__); + return ret; + }*/ + ret = slip_write_data(buf + buf_len, sizeof(buf) - buf_len, payload, payload_len); + if (ret < 0) + return ret; + buf_len += ret; + } + + cpu_to_le16s(crc); + /*ret = slip_send_data(sdev, (u8 *)&crc, 2, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: FCS failed\n", __func__); + return ret; + } + + ret = slip_send_end(sdev, timeout); + if (ret) { + dev_err(&sdev->dev, "%s: trailing END failed\n", __func__); + return ret; + }*/ + + ret = slip_write_data(buf + buf_len, sizeof(buf) - buf_len, (u8 *)&crc, 2); + if (ret < 0) + return ret; + buf_len += ret; + + buf[buf_len++] = SLIP_END; + + slip_print_bytes(buf, buf_len); + + return serdev_device_write(sdev, buf, buf_len, timeout); + + //printk("\n"); + + //return 0; +} + +static int wimod_hci_devmgmt_status(u8 status) +{ + switch (status) { + case DEVMGMT_STATUS_OK: + return 0; + default: + pr_info("DEVMGMT status %u\n", (int)status); + return -EINVAL; + } +} + +static int wimod_hci_devmgmt_send_sync(struct wimod_device *wmdev, + u8 req_msg_id, const u8 *req_payload, int req_payload_len, + u8 rsp_msg_id, u8 **rsp_payload, int *rsp_payload_len, + unsigned long timeout) +{ + struct wimod_hci_packet_completion packet = {0}; + int ret; + + if (rsp_payload && !rsp_payload_len) + return -EINVAL; + + packet.disp.dst_id = DEVMGMT_ID; + packet.disp.msg_id = rsp_msg_id; + packet.disp.dispatchee = wimod_hci_packet_dispatch_completion; + init_completion(&packet.comp); + + wimod_hci_add_dispatcher(wmdev, &packet.disp); + + ret = wimod_hci_send(wmdev->serdev, DEVMGMT_ID, req_msg_id, req_payload, req_payload_len, timeout); + if (ret) { + wimod_hci_remove_dispatcher(wmdev, &(packet.disp)); + return ret; + } + + timeout = wait_for_completion_timeout(&packet.comp, timeout); + wimod_hci_remove_dispatcher(wmdev, &packet.disp); + if (!timeout) + return -ETIMEDOUT; + + if (packet.payload_len < 1) { + kfree(packet.payload); + return -EINVAL; + } + + ret = wimod_hci_devmgmt_status(packet.payload[0]); + if (ret || !rsp_payload) + kfree(packet.payload); + else if (rsp_payload) { + *rsp_payload = packet.payload; + *rsp_payload_len = packet.payload_len; + } + return ret; +} + +static int wimod_hci_ping(struct wimod_device *wmdev, unsigned long timeout) +{ + return wimod_hci_devmgmt_send_sync(wmdev, + DEVMGMT_MSG_PING_REQ, NULL, 0, + DEVMGMT_MSG_PING_RSP, NULL, NULL, + timeout); +} + +static int wimod_hci_get_device_info(struct wimod_device *wmdev, u8 *buf, unsigned long timeout) +{ + u8 *payload; + int payload_len; + int ret; + + ret = wimod_hci_devmgmt_send_sync(wmdev, + DEVMGMT_MSG_GET_DEVICE_INFO_REQ, NULL, 0, + DEVMGMT_MSG_GET_DEVICE_INFO_RSP, &payload, &payload_len, + timeout); + if (ret) + return ret; + + if (payload_len < 10) { + dev_err(&wmdev->serdev->dev, "get_device_info: payload length (10)\n"); + kfree(payload); + return -EINVAL; + } + + if (buf) + memcpy(buf, payload + 1, min(payload_len - 1, 9)); + + kfree(payload); + return 0; +} + +static int wimod_hci_get_fw_info(struct wimod_device *wmdev, u8 **info, int *info_len, unsigned long timeout) +{ + u8 *payload; + int payload_len; + int ret; + + if (info && !info_len) + return -EINVAL; + + ret = wimod_hci_devmgmt_send_sync(wmdev, + DEVMGMT_MSG_GET_FW_INFO_REQ, NULL, 0, + DEVMGMT_MSG_GET_FW_INFO_RSP, &payload, &payload_len, + timeout); + if (ret) + return ret; + + if (info) { + *info = payload + 1; + *info_len = payload_len - 1; + } else + kfree(payload); + + return 0; +} + +static void wimod_hci_get_fw_info_free(u8* info) +{ + u8 *payload = info - 1; + + kfree(payload); +} + +static void wimod_process_packet(struct serdev_device *sdev, const u8 *data, int len) +{ + struct wimod_device *wmdev = serdev_device_get_drvdata(sdev); + struct wimod_hci_packet_dispatcher *e; + u16 crc; + + dev_info(&sdev->dev, "Processing incoming packet (%d)\n", len); + + if (len < 4) { + dev_dbg(&sdev->dev, "Discarding packet of length %d\n", len); + return; + } + + crc = ~crc_ccitt(0xffff, data, len); + if (crc != 0x0f47) { + dev_dbg(&sdev->dev, "Discarding packet with wrong checksum\n"); + return; + } + + list_for_each_entry(e, &wmdev->packet_dispatchers, list) { + if (e->dst_id == data[0] && e->msg_id == data[1]) { + e->dispatchee(data, len - 2, e); + break; + } + } +} + +static int wimod_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count) +{ + struct wimod_device *wmdev = serdev_device_get_drvdata(sdev); + size_t i = 0; + int len = 0; + + dev_dbg(&sdev->dev, "Receive (%d)\n", (int)count); + + while (i < min(count, sizeof(wmdev->rx_buf) - wmdev->rx_len)) { + if (wmdev->rx_esc) { + wmdev->rx_esc = false; + switch (data[i]) { + case SLIP_ESC_END: + wmdev->rx_buf[wmdev->rx_len++] = SLIP_END; + break; + case SLIP_ESC_ESC: + wmdev->rx_buf[wmdev->rx_len++] = SLIP_ESC; + break; + default: + dev_warn(&sdev->dev, "Ignoring unknown escape sequence 0300 0%o\n", data[i]); + break; + } + len += i + 1; + data += i + 1; + count -= i + 1; + i = 0; + continue; + } + if (data[i] != SLIP_END && + data[i] != SLIP_ESC) { + i++; + continue; + } + if (i > 0) { + memcpy(&wmdev->rx_buf[wmdev->rx_len], data, i); + wmdev->rx_len += i; + } + if (data[i] == SLIP_END && wmdev->rx_len > 0) { + wimod_process_packet(sdev, wmdev->rx_buf, wmdev->rx_len); + wmdev->rx_len = 0; + } else if (data[i] == SLIP_ESC) { + wmdev->rx_esc = true; + } + len += i + 1; + data += i + 1; + count -= i + 1; + i = 0; + } + + dev_dbg(&sdev->dev, "Receive: processed %d\n", len); + + return len; +} + +static const struct serdev_device_ops wimod_serdev_client_ops = { + .receive_buf = wimod_receive_buf, + .write_wakeup = serdev_device_write_wakeup, +}; + +static int wimod_probe(struct serdev_device *sdev) +{ + struct wimod_device *wmdev; + u8 buf[9]; + u8 *data; + int data_len; + int ret; + + dev_info(&sdev->dev, "Probing"); + + wmdev = devm_kzalloc(&sdev->dev, sizeof(struct wimod_device), GFP_KERNEL); + if (!wmdev) + return -ENOMEM; + + wmdev->serdev = sdev; + INIT_LIST_HEAD(&wmdev->packet_dispatchers); + serdev_device_set_drvdata(sdev, wmdev); + + ret = serdev_device_open(sdev); + if (ret) { + dev_err(&sdev->dev, "Failed to open (%d)\n", ret); + return ret; + } + + serdev_device_set_baudrate(sdev, 115200); + serdev_device_set_flow_control(sdev, false); + serdev_device_set_client_ops(sdev, &wimod_serdev_client_ops); + + ret = wimod_hci_ping(wmdev, HZ); + if (ret) { + dev_err(&sdev->dev, "Ping failed (%d)\n", ret); + goto err; + } + + ret = wimod_hci_get_device_info(wmdev, buf, HZ); + if (ret) { + dev_err(&sdev->dev, "Failed to obtain device info (%d)\n", ret); + goto err; + } + dev_info(&sdev->dev, "Module type: 0x%02x\n", (int)buf[0]); + + ret = wimod_hci_get_fw_info(wmdev, &data, &data_len, HZ); + if (ret) { + dev_err(&sdev->dev, "Failed to obtain firmware info (%d)\n", ret); + goto err; + } + dev_info(&sdev->dev, "Firmware: %u.%u build %u '%s'\n", + data[1], data[0], ((u16)data[3] << 8) | data[2], data + 4); + wimod_hci_get_fw_info_free(data); + + dev_info(&sdev->dev, "Done.\n"); + + return 0; +err: + serdev_device_close(sdev); + return ret; +} + +static void wimod_remove(struct serdev_device *sdev) +{ + serdev_device_close(sdev); + + dev_info(&sdev->dev, "Removed\n"); +} + +static const struct of_device_id wimod_of_match[] = { + { .compatible = "imst,wimod-hci" }, + {} +}; +MODULE_DEVICE_TABLE(of, wimod_of_match); + +static struct serdev_device_driver wimod_serdev_driver = { + .probe = wimod_probe, + .remove = wimod_remove, + .driver = { + .name = "wimod", + .of_match_table = wimod_of_match, + }, +}; + +static int __init wimod_init(void) +{ + int ret; + + ret = serdev_device_driver_register(&wimod_serdev_driver); + if (ret) + return ret; + + return 0; +} + +static void __exit wimod_exit(void) +{ + serdev_device_driver_unregister(&wimod_serdev_driver); +} + +module_init(wimod_init); +module_exit(wimod_exit); + +MODULE_DESCRIPTION("WiMOD serdev driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); From patchwork Sun Jul 1 11:08:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937565 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="eVPpqxBz"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSdn6WPjz9s1b for ; Sun, 1 Jul 2018 21:22:05 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=OkHs0mtPMMqelfMSPxhTAdF8IWvf0yzQcusDrkz9tZ0=; b=eVPpqxBzxXYaee TV24+N+ZPptWZoz5/zqHxn36xz1T0x67IIkJ7ll46KreHiWqzZzADl6FP8kEaKpiP9MpE5S08Asjc ZOvDBAkRRAqSOaqbmz6mAxcqZ2KoKaa3JkMu0LQ+S84sppoy5FdvNi8m7ofXSy3vn/fzgHgwtoyD8 M0F3jL4frWofwv5JGkWd3X6MhRSW2MPURWnL046bQaltORP/TUX8UrNFlIpH6OPHk2zkPiqwlSk/E Es4QJQb3qunExESXgM9DughVndRcPyf9syuX45KIjndQ7lAFI9YG0t95L6eCTVPYcWn12khfd0cs0 WzvEznyFM/k5pg6Nf+9A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaQZ-0004aA-0j; Sun, 01 Jul 2018 11:21:59 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004YH-94 for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:48 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 44ED3AFA4; Sun, 1 Jul 2018 11:09:02 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 12/15] net: lora: Add USI WM-SG-SM-42 Date: Sun, 1 Jul 2018 13:08:01 +0200 Message-Id: <20180701110804.32415-13-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_335208_F22F2338 X-CRM114-Status: GOOD ( 18.49 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org The USI WM-SG-SM-42 offers a UART based AT command interface. Cc: Dollar Chen (陳義元) Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 7 + drivers/net/lora/Makefile | 3 + drivers/net/lora/usi.c | 411 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 drivers/net/lora/usi.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 2e05caef8645..72a9d2a0f2be 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -31,6 +31,13 @@ config LORA_SX1276 help Semtech SX1272/1276/1278 +config LORA_USI + tristate "USI WM-SG-SM-42 driver" + default y + depends on SERIAL_DEV_BUS + help + USI WM-SG-SM-42 + config LORA_WIMOD tristate "IMST WiMOD driver" default y diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index ecb326c859a5..dfa9a43dcfb3 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -16,5 +16,8 @@ lora-rn2483-y += rn2483_cmd.o obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o lora-sx1276-y := sx1276.o +obj-$(CONFIG_LORA_USI) += lora-usi.o +lora-usi-y := usi.o + obj-$(CONFIG_LORA_WIMOD) += lora-wimod.o lora-wimod-y := wimod.o diff --git a/drivers/net/lora/usi.c b/drivers/net/lora/usi.c new file mode 100644 index 000000000000..f0c697e2cde2 --- /dev/null +++ b/drivers/net/lora/usi.c @@ -0,0 +1,411 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * USI WM-SG-SM-42 + * + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include + +struct usi_device { + struct serdev_device *serdev; + + int mode; + + char rx_buf[4096]; + int rx_len; + + struct completion prompt_recv_comp; + struct completion tx_event_recv_comp; +}; + +static bool usi_cmd_ok(const char *resp) +{ + int len = strlen(resp); + + return (len == 4 && !strcmp(resp, "OK\r\n")) || + (len >= 6 && !strcmp(resp + len - 6, "\r\nOK\r\n")); +} + +static int usi_send_command(struct usi_device *usidev, const char *cmd, char **data, unsigned long timeout) +{ + struct serdev_device *sdev = usidev->serdev; + const char cr = '\r'; + int cmd_len, resp_len; + char *resp; + + cmd_len = strlen(cmd); + serdev_device_write_buf(sdev, cmd, cmd_len); + serdev_device_write_buf(sdev, &cr, 1); + + timeout = wait_for_completion_timeout(&usidev->prompt_recv_comp, timeout); + if (!timeout) + return -ETIMEDOUT; + + resp = usidev->rx_buf; + resp_len = usidev->rx_len; + if (!strncmp(resp, cmd, cmd_len) && resp[cmd_len] == '\r') { + dev_dbg(&sdev->dev, "Skipping echo\n"); + resp += cmd_len + 1; + resp_len -= cmd_len + 1; + } + dev_dbg(&sdev->dev, "Received: '%s'\n", resp); + if (data) + *data = kstrdup(resp, GFP_KERNEL); + + usidev->rx_len = 0; + reinit_completion(&usidev->prompt_recv_comp); + + return 0; +} + +static int usi_simple_cmd(struct usi_device *usidev, const char *cmd, unsigned long timeout) +{ + char *resp; + int ret; + + ret = usi_send_command(usidev, cmd, &resp, timeout); + if (ret) + return ret; + + if (strcmp(resp, "OK\r\n") == 0) { + kfree(resp); + return 0; + } + + kfree(resp); + + return -EINVAL; +} + +static int usi_cmd_reset(struct usi_device *usidev) +{ + int ret; + + ret = usi_send_command(usidev, "ATZ", NULL, HZ); + if (ret) + return ret; + + mdelay(1000); + + return 0; +} + +static int usi_cmd_read_reg(struct usi_device *usidev, u8 addr, u8 *val) +{ + char *cmd; + char *resp; + char *sz; + int ret; + + cmd = kasprintf(GFP_KERNEL, "AT+RREG=0x%02x", (int)addr); + if (!cmd) + return -ENOMEM; + + ret = usi_send_command(usidev, cmd, &resp, HZ); + if (ret) { + kfree(cmd); + return ret; + } + if (!usi_cmd_ok(resp)) { + kfree(resp); + kfree(cmd); + return -EINVAL; + } + resp[strlen(resp) - 6] = '\0'; + sz = resp; + if (strstarts(sz, "+Reg=")) + sz += 5; + if (strncasecmp(sz, cmd + 8, 4) == 0 && strstarts(sz + 4, ", ")) + sz += 6; + + kfree(cmd); + + dev_dbg(&usidev->serdev->dev, "Parsing '%s'\n", sz); + ret = kstrtou8(sz, 0, val); + if (ret) { + kfree(resp); + return ret; + } + + kfree(resp); + + return 0; +} + +static int usi_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count) +{ + struct usi_device *usidev = serdev_device_get_drvdata(sdev); + size_t i = 0; + int len = 0; + + dev_dbg(&sdev->dev, "Receive (%d)\n", (int)count); + + for (i = 0; i < count; i++) { + dev_dbg(&sdev->dev, "Receive: 0x%02x\n", (int)data[i]); + } + i = 0; + + if (completion_done(&usidev->prompt_recv_comp) || + completion_done(&usidev->tx_event_recv_comp)) { + dev_info(&sdev->dev, "RX waiting on completion\n"); + return 0; + } + if (usidev->rx_len == sizeof(usidev->rx_buf) - 1) { + dev_warn(&sdev->dev, "RX buffer full\n"); + return 0; + } + + i = min(count, sizeof(usidev->rx_buf) - 1 - usidev->rx_len); + if (i > 0) { + memcpy(&usidev->rx_buf[usidev->rx_len], data, i); + usidev->rx_len += i; + len += i; + } + if (usidev->rx_len >= 3 && strncmp(&usidev->rx_buf[usidev->rx_len - 3], "\r# ", 3) == 0) { + usidev->rx_len -= 3; + usidev->rx_buf[usidev->rx_len] = '\0'; + complete(&usidev->prompt_recv_comp); + } else if (usidev->rx_len > 7 && strstarts(usidev->rx_buf, "+RCV") && + strncmp(&usidev->rx_buf[usidev->rx_len - 2], "\r\n", 2) == 0) { + usidev->rx_buf[usidev->rx_len - 2] = '\0'; + dev_info(&sdev->dev, "RCV event: '%s'\n", usidev->rx_buf + 4); + usidev->rx_len = 0; + } else if (usidev->rx_len > 6 && strstarts(usidev->rx_buf, "+TX: ") && + strncmp(&usidev->rx_buf[usidev->rx_len - 2], "\r\n", 2) == 0) { + usidev->rx_buf[usidev->rx_len - 2] = '\0'; + dev_info(&sdev->dev, "TX event: '%s'\n", usidev->rx_buf + 5); + complete(&usidev->tx_event_recv_comp); + } + + return len; +} + +static const struct serdev_device_ops usi_serdev_client_ops = { + .receive_buf = usi_receive_buf, +}; + +static int usi_probe(struct serdev_device *sdev) +{ + struct usi_device *usidev; + //unsigned long timeout; + char *resp; + u8 val; + int ret; + + dev_info(&sdev->dev, "Probing"); + + usidev = devm_kzalloc(&sdev->dev, sizeof(struct usi_device), GFP_KERNEL); + if (!usidev) + return -ENOMEM; + + usidev->serdev = sdev; + usidev->mode = -1; + init_completion(&usidev->prompt_recv_comp); + init_completion(&usidev->tx_event_recv_comp); + serdev_device_set_drvdata(sdev, usidev); + + ret = serdev_device_open(sdev); + if (ret) { + dev_err(&sdev->dev, "Failed to open (%d)", ret); + return ret; + } + + serdev_device_set_baudrate(sdev, 115200); + serdev_device_set_flow_control(sdev, false); + serdev_device_set_client_ops(sdev, &usi_serdev_client_ops); + + ret = usi_cmd_reset(usidev); + if (ret) + dev_warn(&sdev->dev, "Reset failed\n"); + + ret = usi_send_command(usidev, "ATE=0", NULL, HZ); + if (ret) + dev_warn(&sdev->dev, "ATE failed\n"); + + /* Dropped in firmware 2.8 */ + ret = usi_send_command(usidev, "ATI", &resp, HZ); + if (!ret) { + if (usi_cmd_ok(resp)) { + resp[strlen(resp) - 6] = '\0'; + dev_info(&sdev->dev, "Firmware '%s'\n", resp); + } + kfree(resp); + } + + ret = usi_send_command(usidev, "AT+DEFMODE", &resp, HZ); + if (ret) { + dev_err(&sdev->dev, "Checking DEFMODE failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + if (usi_cmd_ok(resp)) { + resp[strlen(resp) - 6] = '\0'; + dev_info(&sdev->dev, "Default mode '%s'\n", resp); + if (!strcmp(resp, "MFG_WAN_MODE")) + usidev->mode = 6; + else if (!strcmp(resp, "MFG_TEST_IDLE")) + usidev->mode = 0; + else if (!strcmp(resp, "MFG_TX_TONE")) + usidev->mode = 1; + else if (!strcmp(resp, "MFG_TX_PACKET")) + usidev->mode = 2; + else if (!strcmp(resp, "MFG_ERROR_LESS_ARGUMENETS")) + usidev->mode = 3; + else if (!strcmp(resp, "MFG_TX_TEXT")) + usidev->mode = 4; + else if (!strcmp(resp, "MFG_TEST_STOP")) + usidev->mode = 5; + } + kfree(resp); + + if (usidev->mode != 3) { + ret = usi_simple_cmd(usidev, "AT+DEFMODE=3", HZ); + if (ret) { + dev_err(&sdev->dev, "Setting DEFMODE failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + +#if 1 + ret = usi_simple_cmd(usidev, "AT+WDCT", 5 * HZ); + if (ret) { + dev_err(&sdev->dev, "Writing DCT failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + + ret = usi_cmd_reset(usidev); + if (ret) { + dev_err(&sdev->dev, "Reset failed\n"); + serdev_device_close(sdev); + return ret; + } + + ret = usi_send_command(usidev, "ATE=0", NULL, HZ); + if (ret) + dev_warn(&sdev->dev, "ATE failed\n"); +#endif + + usidev->mode = -1; + ret = usi_send_command(usidev, "AT+DEFMODE", &resp, HZ); + if (ret) { + dev_err(&sdev->dev, "Checking DEFMODE failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + if (usi_cmd_ok(resp)) { + resp[strlen(resp) - 6] = '\0'; + dev_info(&sdev->dev, "Default mode '%s'\n", resp); + if (!strcmp(resp, "MFG_WAN_MODE")) { + usidev->mode = 6; + } + } + kfree(resp); + } + + ret = usi_send_command(usidev, "AT+VER", &resp, HZ); + if (!ret) { + if (usi_cmd_ok(resp)) { + resp[strlen(resp) - 6] = '\0'; + dev_info(&sdev->dev, "LoRaWAN version '%s'\n", + (strstarts(resp, "+VER=")) ? (resp + 5) : resp); + } + kfree(resp); + } + + ret = usi_simple_cmd(usidev, "AT+RF=20,868000000,7,0,1,0,8,0,0,0", HZ); + if (ret) { + dev_err(&sdev->dev, "AT+RF failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + + /*ret = usi_simple_cmd(usidev, "AT+TXT=1,deadbeef", 2 * HZ); + if (ret) { + dev_err(&sdev->dev, "TX failed (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + + timeout = wait_for_completion_timeout(&usidev->tx_event_recv_comp, 5 * HZ); + if (!timeout) { + serdev_device_close(sdev); + return -ETIMEDOUT; + } + usidev->rx_len = 0; + reinit_completion(&usidev->tx_event_recv_comp);*/ + + ret = usi_cmd_read_reg(usidev, 0x42, &val); + if (!ret) { + dev_info(&sdev->dev, "SX1272 VERSION 0x%02x\n", (int)val); + } + + ret = usi_cmd_read_reg(usidev, 0x39, &val); + if (!ret) { + dev_info(&sdev->dev, "SX1272 SyncWord 0x%02x\n", (int)val); + } + + ret = usi_cmd_read_reg(usidev, 0x01, &val); + if (!ret) { + dev_info(&sdev->dev, "SX1272 OpMode 0x%02x\n", (int)val); + } + + dev_info(&sdev->dev, "Done."); + + return 0; +} + +static void usi_remove(struct serdev_device *sdev) +{ + struct usi_device *usidev = serdev_device_get_drvdata(sdev); + + usi_send_command(usidev, "ATE=1\r", NULL, HZ); + + serdev_device_close(sdev); + + dev_info(&sdev->dev, "Removed\n"); +} + +static const struct of_device_id usi_of_match[] = { + { .compatible = "usi,wm-sg-sm-42" }, + {} +}; +MODULE_DEVICE_TABLE(of, usi_of_match); + +static struct serdev_device_driver usi_serdev_driver = { + .probe = usi_probe, + .remove = usi_remove, + .driver = { + .name = "usi", + .of_match_table = usi_of_match, + }, +}; + +static int __init usi_init(void) +{ + int ret; + + ret = serdev_device_driver_register(&usi_serdev_driver); + if (ret) + return ret; + + return 0; +} + +static void __exit usi_exit(void) +{ + serdev_device_driver_unregister(&usi_serdev_driver); +} + +module_init(usi_init); +module_exit(usi_exit); + +MODULE_DESCRIPTION("USI WM-SG-SM-42 serdev driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); From patchwork Sun Jul 1 11:08:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937564 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="V1IPerkS"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSdS6TdYz9s1b for ; Sun, 1 Jul 2018 21:21:48 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=MUEyoXnYALwG2HlM8czTqfTGFyQruCJJc1XdMRWbUpk=; b=V1IPerkSyUsqa2 GSwlTtf/keY2tHsgv7AoFojMwc6H3N9klehjsXUCwqQYO6Rg5MjjHs/106EqTo4thMfJEjr2IsgH2 a4b3iXmR7F3h0KJ5MKVH++YOCOzKFB7elnZvy86F8D1XjJWoG2mwk7q1HxLd3zHHgjGf/6/GyfFkD Zf3vzBBcvca0aVatc4OpzFU/+r0SmxoB4tWbvcYdFSRkJB3YS81ctXtUfr+uBia6kuYpcNshJ1o0y Y4Zo753ftM4cA0NtirSNKPrNCtLe5laioZ3kTRQhTv1WIWYpVOj9uxlrBCgJXRevaGFX4+7QRdUHr PgIA5IkxyWjViGoJ1DHA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaQD-0004Fx-Lu; Sun, 01 Jul 2018 11:21:37 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004aS-9k for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:41 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id F2471AFA5; Sun, 1 Jul 2018 11:09:02 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 13/15] net: lora: Prepare RAK RAK811 Date: Sun, 1 Jul 2018 13:08:02 +0200 Message-Id: <20180701110804.32415-14-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_620734_48C5FC4B X-CRM114-Status: GOOD ( 16.47 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , Jiri Pirko , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org The RAK811 and RAK812 offer a UART based AT command interface. It allows both LoRaWAN and LoRa modes. Cc: Ken Yu (禹凯) Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 7 ++ drivers/net/lora/Makefile | 3 + drivers/net/lora/rak811.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+) create mode 100644 drivers/net/lora/rak811.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 72a9d2a0f2be..3e384493cbdd 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -17,6 +17,13 @@ config LORA_DEV if LORA_DEV +config LORA_RAK811 + tristate "RAK RAK811 driver" + default y + depends on SERIAL_DEV_BUS + help + RAK RAK811/RAK812 + config LORA_RN2483 tristate "Microchip RN2483/RN2903 driver" default y diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index dfa9a43dcfb3..6b6870ffbfd8 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -9,6 +9,9 @@ lora-dev-y := dev.o # Alphabetically sorted. # +obj-$(CONFIG_LORA_RAK811) += lora-rak811.o +lora-rak811-y := rak811.o + obj-$(CONFIG_LORA_RN2483) += lora-rn2483.o lora-rn2483-y := rn2483.o lora-rn2483-y += rn2483_cmd.o diff --git a/drivers/net/lora/rak811.c b/drivers/net/lora/rak811.c new file mode 100644 index 000000000000..ad3d0980c489 --- /dev/null +++ b/drivers/net/lora/rak811.c @@ -0,0 +1,219 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * RAK RAK811 + * + * Copyright (c) 2017-2018 Andreas Färber + */ + +#include +#include +#include +#include +#include +#include +#include + +struct rak811_device { + struct serdev_device *serdev; + + char rx_buf[4096]; + int rx_len; + + struct completion line_recv_comp; +}; + +static int rak811_send_command(struct rak811_device *rakdev, const char *cmd, char **data, unsigned long timeout) +{ + struct serdev_device *sdev = rakdev->serdev; + const char *crlf = "\r\n"; + char *resp; + + serdev_device_write_buf(sdev, cmd, strlen(cmd)); + serdev_device_write_buf(sdev, crlf, 2); + + timeout = wait_for_completion_timeout(&rakdev->line_recv_comp, timeout); + if (!timeout) + return -ETIMEDOUT; + + resp = rakdev->rx_buf; + dev_dbg(&sdev->dev, "Received: '%s'\n", resp); + if (data) + *data = kstrdup(resp, GFP_KERNEL); + + rakdev->rx_len = 0; + reinit_completion(&rakdev->line_recv_comp); + + return 0; +} + +static int rak811_simple_cmd(struct rak811_device *rakdev, const char *cmd, unsigned long timeout) +{ + char *resp; + int ret; + + ret = rak811_send_command(rakdev, cmd, &resp, timeout); + if (ret) + return ret; + + if (strncmp(resp, "OK", 2) == 0) { + kfree(resp); + return 0; + } + + kfree(resp); + + return -EINVAL; +} + +static int rak811_get_version(struct rak811_device *rakdev, char **version, unsigned long timeout) +{ + char *resp; + int ret; + + ret = rak811_send_command(rakdev, "at+version", &resp, timeout); + if (ret) + return ret; + + if (strncmp(resp, "OK", 2) == 0) { + *version = kstrdup(resp + 2, GFP_KERNEL); + kfree(resp); + return 0; + } + + kfree(resp); + + return -EINVAL; +} + +static int rak811_receive_buf(struct serdev_device *sdev, const u8 *data, size_t count) +{ + struct rak811_device *rakdev = serdev_device_get_drvdata(sdev); + size_t i = 0; + int len = 0; + + dev_dbg(&sdev->dev, "Receive (%d)\n", (int)count); + + for (i = 0; i < count; i++) { + dev_dbg(&sdev->dev, "Receive: 0x%02x\n", (int)data[i]); + } + + if (completion_done(&rakdev->line_recv_comp)) { + dev_info(&sdev->dev, "RX waiting on completion\n"); + return 0; + } + if (rakdev->rx_len == sizeof(rakdev->rx_buf) - 1) { + dev_warn(&sdev->dev, "RX buffer full\n"); + return 0; + } + + i = min(count, sizeof(rakdev->rx_buf) - 1 - rakdev->rx_len); + if (i > 0) { + memcpy(&rakdev->rx_buf[rakdev->rx_len], data, i); + rakdev->rx_len += i; + len += i; + } + if (rakdev->rx_len >= 2 && strncmp(&rakdev->rx_buf[rakdev->rx_len - 2], "\r\n", 2) == 0) { + rakdev->rx_len -= 2; + rakdev->rx_buf[rakdev->rx_len] = '\0'; + complete(&rakdev->line_recv_comp); + } + + return len; +} + +static const struct serdev_device_ops rak811_serdev_client_ops = { + .receive_buf = rak811_receive_buf, +}; + +static int rak811_probe(struct serdev_device *sdev) +{ + struct rak811_device *rakdev; + char *sz; + int ret; + + dev_info(&sdev->dev, "Probing\n"); + + rakdev = devm_kzalloc(&sdev->dev, sizeof(struct rak811_device), GFP_KERNEL); + if (!rakdev) + return -ENOMEM; + + rakdev->serdev = sdev; + init_completion(&rakdev->line_recv_comp); + serdev_device_set_drvdata(sdev, rakdev); + + ret = serdev_device_open(sdev); + if (ret) { + dev_err(&sdev->dev, "Failed to open (%d)\n", ret); + return ret; + } + + serdev_device_set_baudrate(sdev, 115200); + serdev_device_set_flow_control(sdev, false); + serdev_device_set_client_ops(sdev, &rak811_serdev_client_ops); + + ret = rak811_get_version(rakdev, &sz, HZ); + if (ret) { + dev_err(&sdev->dev, "Failed to get version (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + + dev_info(&sdev->dev, "firmware version: %s\n", sz); + kfree(sz); + + ret = rak811_simple_cmd(rakdev, "at+mode=1", 2 * HZ); + if (ret) { + dev_err(&sdev->dev, "Failed to set mode to P2P (%d)\n", ret); + serdev_device_close(sdev); + return ret; + } + + dev_info(&sdev->dev, "Done.\n"); + + return 0; +} + +static void rak811_remove(struct serdev_device *sdev) +{ + serdev_device_close(sdev); + + dev_info(&sdev->dev, "Removed\n"); +} + +static const struct of_device_id rak811_of_match[] = { + { .compatible = "rakwireless,rak811" }, + {} +}; +MODULE_DEVICE_TABLE(of, rak811_of_match); + +static struct serdev_device_driver rak811_serdev_driver = { + .probe = rak811_probe, + .remove = rak811_remove, + .driver = { + .name = "rak811", + .of_match_table = rak811_of_match, + }, +}; + +static int __init rak811_init(void) +{ + int ret; + + ret = serdev_device_driver_register(&rak811_serdev_driver); + if (ret) + return ret; + + return 0; +} + +static void __exit rak811_exit(void) +{ + serdev_device_driver_unregister(&rak811_serdev_driver); +} + +module_init(rak811_init); +module_exit(rak811_exit); + +MODULE_DESCRIPTION("RAK811 serdev driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); From patchwork Sun Jul 1 11:08:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937563 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="Fco7CAk0"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JSd00R2Zz9s1b for ; Sun, 1 Jul 2018 21:21:23 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=x8sh1U+Oge9YuPZFcquJWsnIHZ5qUdFuchvkysUFK2o=; b=Fco7CAk0ji41It IoUTVVMfNNPwC8DXHLZz/4bE5XSfe5Gd4ILc/aZvbTEc3vVed3TuRCf4Qpy1cPPryXrGwrkd/thXB xaQ9GRF8wkaGElACnfvVsvWkZovaM5H+8EFfTsxUzxkl6zioIv5Y7EouPm0hzXRBBQoqO/TAciAZC 4njQIOhJr3YkIf0tqcKQSKwQ8rtch4QQvEdBQLx23zVONyNshQpOU5QRF3cB/dffPlTcwHtuvkiMb Fb6JSMkKP84QSSZm1vDnbw3mpS3HwQNRDpEs+/3C+rPwPDFHhccx6y3I2Jo/4xu8myZvabbUtdaC6 Lox+KEEFrnyqclg6kaTQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaPv-0003zs-0n; Sun, 01 Jul 2018 11:21:19 +0000 Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEP-0004aT-9B for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:39 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id AD20FAFB3; Sun, 1 Jul 2018 11:09:03 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 14/15] net: lora: Prepare Semtech SX1257 Date: Sun, 1 Jul 2018 13:08:03 +0200 Message-Id: <20180701110804.32415-15-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_040926_258664_BFBA9434 X-CRM114-Status: GOOD ( 14.77 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Steve deRosier , Matthias Brugger , Jiri Pirko , Ben Whitten , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , Mark Brown , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org The Semtech SX1257 and Sx1255 are usually used for radios A/B of SX1301. This will not implement a netdev itself, but rather needs to interface with SX130x somehow. Cc: Ben Whitten Cc: Steve deRosier Cc: Mark Brown Cc: Michael Röder Cc: Ken Yu (禹凯) Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 7 ++++ drivers/net/lora/Makefile | 3 ++ drivers/net/lora/sx1257.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 drivers/net/lora/sx1257.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 3e384493cbdd..68c7480d7812 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -31,6 +31,13 @@ config LORA_RN2483 help Microchip RN2483/2903 +config LORA_SX1257 + tristate "Semtech SX125x SPI driver" + default y + depends on SPI + help + Semtech SX1255/1257 + config LORA_SX1276 tristate "Semtech SX127x SPI driver" default y diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index 6b6870ffbfd8..44c578bde7d5 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -16,6 +16,9 @@ obj-$(CONFIG_LORA_RN2483) += lora-rn2483.o lora-rn2483-y := rn2483.o lora-rn2483-y += rn2483_cmd.o +obj-$(CONFIG_LORA_SX1257) += lora-sx1257.o +lora-sx1257-y := sx1257.o + obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o lora-sx1276-y := sx1276.o diff --git a/drivers/net/lora/sx1257.c b/drivers/net/lora/sx1257.c new file mode 100644 index 000000000000..c4e04ee3ec4b --- /dev/null +++ b/drivers/net/lora/sx1257.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Semtech SX1255/SX1257 LoRa transceiver + * + * Copyright (c) 2018 Andreas Färber + * + * Based on SX1301 HAL code: + * Copyright (c) 2013 Semtech-Cycleo + */ + +#include +#include +#include +#include + +static int sx1257_write(struct spi_device *spi, u8 reg, u8 val) +{ + u8 buf[2]; + + buf[0] = reg | BIT(7); + buf[1] = val; + return spi_write(spi, buf, 2); +} + +static int sx1257_read(struct spi_device *spi, u8 reg, u8 *val) +{ + u8 addr = reg & 0x7f; + return spi_write_then_read(spi, &addr, 1, val, 1); +} + +static int sx1257_probe(struct spi_device *spi) +{ + u8 val; + int ret; + + if (true) { + ret = sx1257_read(spi, 0x07, &val); + if (ret) { + dev_err(&spi->dev, "version read failed\n"); + return ret; + } + + dev_info(&spi->dev, "SX125x version: %02x\n", (unsigned)val); + } + + ret = sx1257_write(spi, 0x10, 1 /* + 2 */); + if (ret) { + dev_err(&spi->dev, "clk write failed\n"); + return ret; + } + + dev_info(&spi->dev, "clk written\n"); + + if (true) { + ret = sx1257_write(spi, 0x26, 13 + 2 * 16); + if (ret) { + dev_err(&spi->dev, "xosc write failed\n"); + return ret; + } + } + + dev_info(&spi->dev, "SX1257 module probed\n"); + + return 0; +} + +static int sx1257_remove(struct spi_device *spi) +{ + dev_info(&spi->dev, "SX1257 module removed\n"); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id sx1257_dt_ids[] = { + { .compatible = "semtech,sx1255" }, + { .compatible = "semtech,sx1257" }, + {} +}; +MODULE_DEVICE_TABLE(of, sx1257_dt_ids); +#endif + +static struct spi_driver sx1257_spi_driver = { + .driver = { + .name = "sx1257", + .of_match_table = of_match_ptr(sx1257_dt_ids), + }, + .probe = sx1257_probe, + .remove = sx1257_remove, +}; + +module_spi_driver(sx1257_spi_driver); + +MODULE_DESCRIPTION("SX1257 SPI driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL"); From patchwork Sun Jul 1 11:08:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Andreas_F=C3=A4rber?= X-Patchwork-Id: 937575 Return-Path: X-Original-To: incoming-imx@patchwork.ozlabs.org Delivered-To: patchwork-incoming-imx@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.de Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="t/TAIWAu"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=infradead.org header.i=@infradead.org header.b="OqvMS/0y"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41JTqk19gmz9s29 for ; Sun, 1 Jul 2018 22:15:46 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=9QXVcJy3U76J6H/R3y/s5zSsVZoEQaMLNwoE5RnCEMU=; b=t/TAIWAuQ2EQ2y fvZm1+gOOSm2evkTk4OwbkroWBcYwO8OUweSNijQAb+U2FyRmKreBaqosbrjaylggvYgwdPZDJ1rI ILy5EJLHWyWZApdoWnVFFeSEspRnCYgVV2m6ZWajlpFqD1732lwWHmC5Rpy4rSQpktyde4rlr8Kqi TX5TX+G4GbgjmAoGAV1hb3F47e9vyLkZjkaoQiyqUb9tG0rz//Q9eiNf+yrsmNeoUPOaFZwh90Y4d I0riRf4yf9/HTJQOEVb3gsk7So2EIzGimKQ4tpdpRTbpxPzUG4KPJplfDPJBEwv3wCK4xovTCH7UN 3wY8a813OrCzlLlAE4QA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZbGS-0003Rv-Q8; Sun, 01 Jul 2018 12:15:36 +0000 Received: from merlin.infradead.org ([2001:8b0:10b:1231::1]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZb6a-0003Y6-M5 for linux-arm-kernel@bombadil.infradead.org; Sun, 01 Jul 2018 12:05:25 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=merlin.20170209; h=Content-Transfer-Encoding:Content-Type: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From:Sender :Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=811dXG3ep/C87uS6miuCKqZ2X0nHlbnq3jNqB+S7urY=; b=OqvMS/0yOEtGNAyAptZo8dhJmO T5hh8mWQ6nltbN1gdO5TXr4CPRkApn5R+x/gfiIufXpjTv569RMuTkIaaqfwxK3m3/iH9beoZToE2 tmjXXFWYIXVsjebLpULB12eKL4D87mYn5ecediza8+gQBL/Q5whaNkR+or6D+ziE9iRxvpuHM9Tfz jOGjtkfI7rVbVsVulsMWomWpo9RYI0wJTgA+kg1d1MxYDehZwFUshveGZDINgQ2Abduc9EFgEJe+l Mu1ub9Z9TwMDVBQixZg1Jzueb6/BIfYLo9q818EAz9ghAfFsjq7Q9+/QJlVonXjBVf2pGAh/pX70G 7I4dme/g==; Received: from mx2.suse.de ([195.135.220.15] helo=mx1.suse.de) by merlin.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fZaEn-0003dO-9p for linux-arm-kernel@lists.infradead.org; Sun, 01 Jul 2018 11:09:51 +0000 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 74E4DAFBD; Sun, 1 Jul 2018 11:09:04 +0000 (UTC) From: =?utf-8?q?Andreas_F=C3=A4rber?= To: netdev@vger.kernel.org Subject: [RFC net-next 15/15] net: lora: Add Semtech SX1301 Date: Sun, 1 Jul 2018 13:08:04 +0200 Message-Id: <20180701110804.32415-16-afaerber@suse.de> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180701110804.32415-1-afaerber@suse.de> References: <20180701110804.32415-1-afaerber@suse.de> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180701_070949_556277_B4699FB0 X-CRM114-Status: GOOD ( 23.78 ) X-Spam-Score: -2.3 (--) X-Spam-Report: SpamAssassin version 3.4.1 on merlin.infradead.org summary: Content analysis details: (-2.3 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [195.135.220.15 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Steve deRosier , Matthias Brugger , Jiri Pirko , Ben Whitten , Marcel Holtmann , Dollar Chen , linux-kernel@vger.kernel.org, =?utf-8?q?Michael_R=C3=B6der?= , Janus Piwek , linux-spi@vger.kernel.org, Mark Brown , =?utf-8?q?Andreas_F=C3=A4rber?= , Jian-Hong Pan , Ken Yu , "David S . Miller" , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+incoming-imx=patchwork.ozlabs.org@lists.infradead.org List-Id: linux-imx-kernel.lists.patchwork.ozlabs.org The Semtech SX1301 was the first multi-channel LoRa "concentrator". It uses a SPI interface to the host as well as a dual SPI interface to its radios. These two have been implemented as spi_controller, so that the Device Tree can specify whether the respective module uses two SX1257, two SX1255 or a combination of these or some unforeseen chipset. This implementation is the most recent - initialization is not yet complete, it will need to load firmware into the two on-chip MCUs. Unfortunately there is no full datasheet with register descriptions, only a BSD-licensed userspace HAL implementation using spidev devices. Therefore some register names are unknown. Cc: Ben Whitten Cc: Steve deRosier Cc: Mark Brown Cc: Michael Röder Cc: Ken Yu (禹凯) Cc: linux-spi@vger.kernel.org Signed-off-by: Andreas Färber --- drivers/net/lora/Kconfig | 7 + drivers/net/lora/Makefile | 3 + drivers/net/lora/sx1301.c | 446 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 456 insertions(+) create mode 100644 drivers/net/lora/sx1301.c diff --git a/drivers/net/lora/Kconfig b/drivers/net/lora/Kconfig index 68c7480d7812..950450e353b4 100644 --- a/drivers/net/lora/Kconfig +++ b/drivers/net/lora/Kconfig @@ -45,6 +45,13 @@ config LORA_SX1276 help Semtech SX1272/1276/1278 +config LORA_SX1301 + tristate "Semtech SX1301 SPI driver" + default y + depends on SPI + help + Semtech SX1301 + config LORA_USI tristate "USI WM-SG-SM-42 driver" default y diff --git a/drivers/net/lora/Makefile b/drivers/net/lora/Makefile index 44c578bde7d5..1cc1e3aa189b 100644 --- a/drivers/net/lora/Makefile +++ b/drivers/net/lora/Makefile @@ -22,6 +22,9 @@ lora-sx1257-y := sx1257.o obj-$(CONFIG_LORA_SX1276) += lora-sx1276.o lora-sx1276-y := sx1276.o +obj-$(CONFIG_LORA_SX1301) += lora-sx1301.o +lora-sx1301-y := sx1301.o + obj-$(CONFIG_LORA_USI) += lora-usi.o lora-usi-y := usi.o diff --git a/drivers/net/lora/sx1301.c b/drivers/net/lora/sx1301.c new file mode 100644 index 000000000000..5c936c1116d1 --- /dev/null +++ b/drivers/net/lora/sx1301.c @@ -0,0 +1,446 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Semtech SX1301 LoRa concentrator + * + * Copyright (c) 2018 Andreas Färber + * + * Based on SX1301 HAL code: + * Copyright (c) 2013 Semtech-Cycleo + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_PAGE_RESET 0 +#define REG_VERSION 1 +#define REG_2_SPI_RADIO_A_DATA 33 +#define REG_2_SPI_RADIO_A_DATA_READBACK 34 +#define REG_2_SPI_RADIO_A_ADDR 35 +#define REG_2_SPI_RADIO_A_CS 37 +#define REG_2_SPI_RADIO_B_DATA 38 +#define REG_2_SPI_RADIO_B_DATA_READBACK 39 +#define REG_2_SPI_RADIO_B_ADDR 40 +#define REG_2_SPI_RADIO_B_CS 42 + +#define REG_PAGE_RESET_SOFT_RESET BIT(7) + +#define REG_16_GLOBAL_EN BIT(3) + +#define REG_17_CLK32M_EN BIT(0) + +#define REG_2_43_RADIO_A_EN BIT(0) +#define REG_2_43_RADIO_B_EN BIT(1) +#define REG_2_43_RADIO_RST BIT(2) + +struct spi_sx1301 { + struct spi_device *parent; + u8 page; + u8 regs; +}; + +struct sx1301_priv { + struct lora_priv lora; + struct gpio_desc *rst_gpio; + u8 cur_page; + struct spi_controller *radio_a_ctrl, *radio_b_ctrl; +}; + +static int sx1301_read(struct spi_device *spi, u8 reg, u8 *val) +{ + u8 addr = reg & 0x7f; + return spi_write_then_read(spi, &addr, 1, val, 1); +} + +static int sx1301_write(struct spi_device *spi, u8 reg, u8 val) +{ + u8 buf[2]; + + buf[0] = reg | BIT(7); + buf[1] = val; + return spi_write(spi, buf, 2); +} + +static int sx1301_page_switch(struct spi_device *spi, u8 page) +{ + struct sx1301_priv *priv = spi_get_drvdata(spi); + int ret; + + if (priv->cur_page == page) + return 0; + + dev_dbg(&spi->dev, "switching to page %u\n", (unsigned)page); + ret = sx1301_write(spi, REG_PAGE_RESET, page & 0x3); + if (ret) { + dev_err(&spi->dev, "switching to page %u failed\n", (unsigned)page); + return ret; + } + + priv->cur_page = page; + + return 0; +} + +static int sx1301_soft_reset(struct spi_device *spi) +{ + return sx1301_write(spi, REG_PAGE_RESET, REG_PAGE_RESET_SOFT_RESET); +} + +#define REG_RADIO_X_DATA 0 +#define REG_RADIO_X_DATA_READBACK 1 +#define REG_RADIO_X_ADDR 2 +#define REG_RADIO_X_CS 4 + +static int sx1301_radio_set_cs(struct spi_controller *ctrl, bool enable) +{ + struct spi_sx1301 *ssx = spi_controller_get_devdata(ctrl); + u8 cs; + int ret; + + dev_dbg(&ctrl->dev, "setting CS to %s\n", enable ? "1" : "0"); + + ret = sx1301_page_switch(ssx->parent, ssx->page); + if (ret) { + dev_warn(&ctrl->dev, "failed to switch page for CS (%d)\n", ret); + return ret; + } + + ret = sx1301_read(ssx->parent, ssx->regs + REG_RADIO_X_CS, &cs); + if (ret) { + dev_warn(&ctrl->dev, "failed to read CS (%d)\n", ret); + cs = 0; + } + + if (enable) + cs |= BIT(0); + else + cs &= ~BIT(0); + + ret = sx1301_write(ssx->parent, ssx->regs + REG_RADIO_X_CS, cs); + if (ret) + dev_warn(&ctrl->dev, "failed to write CS (%d)\n", ret); + + return 0; +} + +static void sx1301_radio_spi_set_cs(struct spi_device *spi, bool enable) +{ + int ret; + + dev_dbg(&spi->dev, "setting SPI CS to %s\n", enable ? "1" : "0"); + + if (enable) + return; + + ret = sx1301_radio_set_cs(spi->controller, enable); + if (ret) + dev_warn(&spi->dev, "failed to write CS (%d)\n", ret); +} + +static int sx1301_radio_spi_transfer_one(struct spi_controller *ctrl, + struct spi_device *spi, struct spi_transfer *xfr) +{ + struct spi_sx1301 *ssx = spi_controller_get_devdata(ctrl); + const u8 *tx_buf = xfr->tx_buf; + u8 *rx_buf = xfr->rx_buf; + int ret; + + if (xfr->len == 0 || xfr->len > 3) + return -EINVAL; + + dev_dbg(&spi->dev, "transferring one (%u)\n", xfr->len); + + ret = sx1301_page_switch(ssx->parent, ssx->page); + if (ret) { + dev_err(&spi->dev, "failed to switch page for transfer (%d)\n", ret); + return ret; + } + + if (tx_buf) { + ret = sx1301_write(ssx->parent, ssx->regs + REG_RADIO_X_ADDR, tx_buf ? tx_buf[0] : 0); + if (ret) { + dev_err(&spi->dev, "SPI radio address write failed\n"); + return ret; + } + + ret = sx1301_write(ssx->parent, ssx->regs + REG_RADIO_X_DATA, (tx_buf && xfr->len >= 2) ? tx_buf[1] : 0); + if (ret) { + dev_err(&spi->dev, "SPI radio data write failed\n"); + return ret; + } + + ret = sx1301_radio_set_cs(ctrl, true); + if (ret) { + dev_err(&spi->dev, "SPI radio CS set failed\n"); + return ret; + } + + ret = sx1301_radio_set_cs(ctrl, false); + if (ret) { + dev_err(&spi->dev, "SPI radio CS unset failed\n"); + return ret; + } + } + + if (rx_buf) { + ret = sx1301_read(ssx->parent, ssx->regs + REG_RADIO_X_DATA_READBACK, &rx_buf[xfr->len - 1]); + if (ret) { + dev_err(&spi->dev, "SPI radio data read failed\n"); + return ret; + } + } + + return 0; +} + +static void sx1301_radio_setup(struct spi_controller *ctrl) +{ + ctrl->mode_bits = SPI_CS_HIGH | SPI_NO_CS; + ctrl->bits_per_word_mask = SPI_BPW_MASK(8); + ctrl->num_chipselect = 1; + ctrl->set_cs = sx1301_radio_spi_set_cs; + ctrl->transfer_one = sx1301_radio_spi_transfer_one; +} + +static int sx1301_probe(struct spi_device *spi) +{ + struct net_device *netdev; + struct sx1301_priv *priv; + struct spi_sx1301 *radio; + struct gpio_desc *rst; + int ret; + u8 val; + + rst = devm_gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(rst)) + return PTR_ERR(rst); + + gpiod_set_value_cansleep(rst, 1); + msleep(100); + gpiod_set_value_cansleep(rst, 0); + msleep(100); + + spi->bits_per_word = 8; + spi_setup(spi); + + ret = sx1301_read(spi, REG_VERSION, &val); + if (ret) { + dev_err(&spi->dev, "version read failed\n"); + goto err_version; + } + + if (val != 103) { + dev_err(&spi->dev, "unexpected version: %u\n", val); + ret = -ENXIO; + goto err_version; + } + + netdev = alloc_loradev(sizeof(*priv)); + if (!netdev) { + ret = -ENOMEM; + goto err_alloc_loradev; + } + + priv = netdev_priv(netdev); + priv->rst_gpio = rst; + priv->cur_page = 0xff; + + spi_set_drvdata(spi, netdev); + SET_NETDEV_DEV(netdev, &spi->dev); + + ret = sx1301_write(spi, REG_PAGE_RESET, 0); + if (ret) { + dev_err(&spi->dev, "page/reset write failed\n"); + return ret; + } + + ret = sx1301_soft_reset(spi); + if (ret) { + dev_err(&spi->dev, "soft reset failed\n"); + return ret; + } + + ret = sx1301_read(spi, 16, &val); + if (ret) { + dev_err(&spi->dev, "16 read failed\n"); + return ret; + } + + val &= ~REG_16_GLOBAL_EN; + + ret = sx1301_write(spi, 16, val); + if (ret) { + dev_err(&spi->dev, "16 write failed\n"); + return ret; + } + + ret = sx1301_read(spi, 17, &val); + if (ret) { + dev_err(&spi->dev, "17 read failed\n"); + return ret; + } + + val &= ~REG_17_CLK32M_EN; + + ret = sx1301_write(spi, 17, val); + if (ret) { + dev_err(&spi->dev, "17 write failed\n"); + return ret; + } + + ret = sx1301_page_switch(spi, 2); + if (ret) { + dev_err(&spi->dev, "page 2 switch failed\n"); + return ret; + } + + ret = sx1301_read(spi, 43, &val); + if (ret) { + dev_err(&spi->dev, "2|43 read failed\n"); + return ret; + } + + val |= REG_2_43_RADIO_B_EN | REG_2_43_RADIO_A_EN; + + ret = sx1301_write(spi, 43, val); + if (ret) { + dev_err(&spi->dev, "2|43 write failed\n"); + return ret; + } + + msleep(500); + + ret = sx1301_read(spi, 43, &val); + if (ret) { + dev_err(&spi->dev, "2|43 read failed\n"); + return ret; + } + + val |= REG_2_43_RADIO_RST; + + ret = sx1301_write(spi, 43, val); + if (ret) { + dev_err(&spi->dev, "2|43 write failed\n"); + return ret; + } + + msleep(5); + + ret = sx1301_read(spi, 43, &val); + if (ret) { + dev_err(&spi->dev, "2|43 read failed\n"); + return ret; + } + + val &= ~REG_2_43_RADIO_RST; + + ret = sx1301_write(spi, 43, val); + if (ret) { + dev_err(&spi->dev, "2|43 write failed\n"); + return ret; + } + + /* radio A */ + + priv->radio_a_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio)); + if (!priv->radio_a_ctrl) { + ret = -ENOMEM; + goto err_radio_a_alloc; + } + + sx1301_radio_setup(priv->radio_a_ctrl); + priv->radio_a_ctrl->dev.of_node = of_get_child_by_name(spi->dev.of_node, "radio-a"); + + radio = spi_controller_get_devdata(priv->radio_a_ctrl); + radio->page = 2; + radio->regs = REG_2_SPI_RADIO_A_DATA; + radio->parent = spi; + + dev_info(&spi->dev, "registering radio A SPI\n"); + + ret = devm_spi_register_controller(&spi->dev, priv->radio_a_ctrl); + if (ret) { + dev_err(&spi->dev, "radio A SPI register failed\n"); + goto err_radio_a_register; + } + + /* radio B */ + + priv->radio_b_ctrl = spi_alloc_master(&spi->dev, sizeof(*radio)); + if (!priv->radio_b_ctrl) { + ret = -ENOMEM; + goto err_radio_b_alloc; + } + + sx1301_radio_setup(priv->radio_b_ctrl); + priv->radio_b_ctrl->dev.of_node = of_get_child_by_name(spi->dev.of_node, "radio-b"); + + radio = spi_controller_get_devdata(priv->radio_b_ctrl); + radio->page = 2; + radio->regs = REG_2_SPI_RADIO_B_DATA; + radio->parent = spi; + + dev_info(&spi->dev, "registering radio B SPI\n"); + + ret = devm_spi_register_controller(&spi->dev, priv->radio_b_ctrl); + if (ret) { + dev_err(&spi->dev, "radio B SPI register failed\n"); + goto err_radio_b_register; + } + + dev_info(&spi->dev, "SX1301 module probed\n"); + + return 0; +err_radio_b_register: + spi_controller_put(priv->radio_b_ctrl); +err_radio_b_alloc: +err_radio_a_register: + spi_controller_put(priv->radio_a_ctrl); +err_radio_a_alloc: + free_loradev(netdev); +err_alloc_loradev: +err_version: + return ret; +} + +static int sx1301_remove(struct spi_device *spi) +{ + struct net_device *netdev = spi_get_drvdata(spi); + + //unregister_loradev(netdev); + free_loradev(netdev); + + dev_info(&spi->dev, "SX1301 module removed\n"); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id sx1301_dt_ids[] = { + { .compatible = "semtech,sx1301" }, + {} +}; +MODULE_DEVICE_TABLE(of, sx1301_dt_ids); +#endif + +static struct spi_driver sx1301_spi_driver = { + .driver = { + .name = "sx1301", + .of_match_table = of_match_ptr(sx1301_dt_ids), + }, + .probe = sx1301_probe, + .remove = sx1301_remove, +}; + +module_spi_driver(sx1301_spi_driver); + +MODULE_DESCRIPTION("SX1301 SPI driver"); +MODULE_AUTHOR("Andreas Färber "); +MODULE_LICENSE("GPL");