From patchwork Thu Feb 2 14:33:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= X-Patchwork-Id: 51958 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp277164wrn; Thu, 2 Feb 2023 06:40:36 -0800 (PST) X-Google-Smtp-Source: AK7set/vVHFfWGp7K+DG7cQLjgGvl1SXPd47GuifHzFuAupnZsAY2CkChPpPJ7axhkcMOCF8WMEL X-Received: by 2002:a62:3003:0:b0:593:e59c:3d2e with SMTP id w3-20020a623003000000b00593e59c3d2emr4978049pfw.16.1675348835982; Thu, 02 Feb 2023 06:40:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675348835; cv=none; d=google.com; s=arc-20160816; b=WVka4OmdK/G1jxzui5fgN+v377e71v9pknkWduXmNSv/OXEgf6fhPM0LluisACVAk3 NqtOQrMEWe91wXNS69EuYPCCCVyW/y6Dp6F+ylarWjC5OPGZbJJv/FleB5gaCryfXGQn tGx2T8js3FIIneyMFx/74DwNYJ1V56Aj3182160MsrFRjXNign8ewOMfhfusm7O9PLdC +AeVQcBk+qKXaqNRt8IK3rDIfmcm84Bxrja5QwxxMd6jntLczB+6pjN1/+biw0dsW4w1 6/q7lsBm25+YrVMAe9zd1eJby5RdjYABxCtJ8qlv28U9XuIHIp3xUZDBgTOZqCKJ4hCL ZKng== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=K8r6DkoETWsIgmS/Xmo5gOSzidDMMFOeOxAXjNrOtJE=; b=yaJsRxKwiA34f1uw/PZv/jSDTOquO9v38/kANq6+n4Mixs1k8HVSMHu6V//+UP3R+l c4z0z5ddnr6IX5chfu5Y5RYuwLoWoK0D0O5+ol3KXISO5CvKhE4OF3n77zS1H22VoLZN AoRP8+4+Gglhdbg9TwntCq3IVtHCpVETgXovoRosphJy39dDlD8xxEw3Gw4bXWDxM9xS y+lhIWTELZGjKxJwBjklhQ3z1Xcq62Dev2M3M4SbJbz/ulvxz2Vo6XVt4KGnuxts/JmX b9lpTaE6rjUo5gw2leE4PxepBdZWCfdHI1pvElKcuDWdEtNn69dvF2ocBZ4cmhoIIM1j BfUQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=RaocD1pH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id t189-20020a6281c6000000b0058dc1d84b4asi23522948pfd.52.2023.02.02.06.40.23; Thu, 02 Feb 2023 06:40:35 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=RaocD1pH; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232468AbjBBOd2 (ORCPT + 99 others); Thu, 2 Feb 2023 09:33:28 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45084 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232450AbjBBOdX (ORCPT ); Thu, 2 Feb 2023 09:33:23 -0500 Received: from mail-ej1-x631.google.com (mail-ej1-x631.google.com [IPv6:2a00:1450:4864:20::631]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 61DBC70D66; Thu, 2 Feb 2023 06:33:13 -0800 (PST) Received: by mail-ej1-x631.google.com with SMTP id me3so6477014ejb.7; Thu, 02 Feb 2023 06:33:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=K8r6DkoETWsIgmS/Xmo5gOSzidDMMFOeOxAXjNrOtJE=; b=RaocD1pHp6TJyQCWEcVek7fYJPOy+7+RuO0Edq73pthLuJR6LV7KHHywomUoHYd2+l X17/W41UsrEAoNleicS34D/rMEYs7+NI5omwaMgYmPNB3XU3faIorut46kHnGmUiKKEF jD+FwwXcOvTg3zrVW+u5Zbr+pJSL/LFRzYdKTex0kt71RHSw+b2VvSyAMYvOoo9BL9e0 0tckVecGLmx91as4l7PE5gKIMRP8MdjPFMeovPgI3QkWCTyijErwTWy/9fE65MWvkXoC 4/AeMItSxOuARiDOmnD06zyMj6KUSYtw80aAKPveNARuX8+0LpR3HTTdYr8T3TeHsLkJ Gsdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=K8r6DkoETWsIgmS/Xmo5gOSzidDMMFOeOxAXjNrOtJE=; b=Go/DtK1vlb4rbHHVX4Q7TBk3udp6mcYYkVyYHcn/UlJBin9v3jovOJpninTcFk8nAo HC48yrMciMbt9Z6MTzoWe1zo4k6Lt22byjyLZIaWEKOZpUo5DaxXVPeHJhZp2nJc3TSb EIrJ9Ihjvd5pLAkDLM6wi8o/L3V0a+6V3cjUVkLAVNxdS4d+7Bqvb5oNBaXi78LiR9xf dZfHUuX40o2yfJUFl0jx8+wvuCNbJ6UKgdAs0ABp0ju2uU9jPgCNzexg4Bs9r8uTqtDz S2aRyvw48vENkYZWOlTtoYA0cr6mWYlzJtiR8Fipb0RbdbFRqWnwH+4gFsCtwv3BAeNb HhgA== X-Gm-Message-State: AO0yUKWtSKfg/VjDrnjFIJ4Q2QZTorAKjtSRh+oey6P9rQFcr4AV3YTv R5qOI52bx/hPagv5jTllFPdAe7abiqT8Wg== X-Received: by 2002:a17:906:ccce:b0:872:ec40:65e9 with SMTP id ot14-20020a170906ccce00b00872ec4065e9mr6465557ejb.18.1675348391611; Thu, 02 Feb 2023 06:33:11 -0800 (PST) Received: from fedora.local.tbs-biometrics.cz (176-74-132-138.netdatacomm.cz. [176.74.132.138]) by smtp.gmail.com with ESMTPSA id h17-20020a1709066d9100b0087856bd9dbbsm11814237ejt.97.2023.02.02.06.33.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Feb 2023 06:33:11 -0800 (PST) From: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= To: linux-kernel@vger.kernel.org Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, gregkh@linuxfoundation.org, martin.petersen@oracle.com, beanhuo@micron.com, arnd@arndb.de, avri.altman@wdc.com, iwona.winiarska@intel.com, fmdefrancesco@gmail.com, dipenp@nvidia.com, ogabbay@kernel.org, bvanassche@acm.org, mathieu.poirier@linaro.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, devicetree@vger.kernel.org, linus.walleij@linaro.org, =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= Subject: [PATCHv2 1/4] dt-bindings: wiegand: add Wiegand controller common properties Date: Thu, 2 Feb 2023 15:33:02 +0100 Message-Id: <20230202143305.21789-2-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230202143305.21789-1-m.zatovic1@gmail.com> References: <20230202143305.21789-1-m.zatovic1@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756730581081123750?= X-GMAIL-MSGID: =?utf-8?q?1756730581081123750?= Weigand bus is defined by a Wiegand controller node. This node can contain one or more device nodes for devices attached to the controller(it is advised to only connect one device as Wiegand is a point-to-point bus). Wiegand controller needs to specify several attributes such as the pulse length in order to function properly. These attributes are documented here. Signed-off-by: Martin Zaťovič --- .../bindings/wiegand/wiegand-controller.yaml | 50 +++++++++++++++++++ MAINTAINERS | 5 ++ 2 files changed, 55 insertions(+) create mode 100644 Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml diff --git a/Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml b/Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml new file mode 100644 index 000000000000..fed90e01e56f --- /dev/null +++ b/Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/wiegand/wiegand-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Wiegand Generic Controller Common Properties + +maintainers: + - Martin Zaťovič + +description: + Wiegand busses can be described with a node for the Wiegand controller device + and a set of child nodes for each SPI slave on the bus. + +properties: + $nodename: + pattern: "^wiegand(@.*|-[0-9a-f])?$" + + pulse-len-us: + description: | + Length of the low pulse in microseconds. + + interval-len-us: + description: | + Length of a whole bit (both the pulse and the high phase) in microseconds. + + frame-gap-us: + description: | + Length of the last bit of a frame (both the pulse and the high phase) in + microseconds. + +required: + - compatible + - pulse-len-us + - interval-len-us + - frame-gap-us + +additionalProperties: true + +examples: + - | + wiegand@f00 { + compatible = "wiegand-foo"; + pulse-len-us = <50>; + interval-len-us = <2000>; + frame-gap-us = <2000>; + + /* devices */ + }; diff --git a/MAINTAINERS b/MAINTAINERS index 7f86d02cb427..db9624d93af0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22428,6 +22428,11 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/hid/hid-wiimote* +WIEGAND BUS DRIVER +M: Martin Zaťovič +S: Maintained +F: Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml + WILOCITY WIL6210 WIRELESS DRIVER L: linux-wireless@vger.kernel.org S: Orphan From patchwork Thu Feb 2 14:33:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= X-Patchwork-Id: 51959 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp277368wrn; Thu, 2 Feb 2023 06:41:00 -0800 (PST) X-Google-Smtp-Source: AK7set9sWy44+DJW/pqmWolSJMy3bCfV9aPrWhTX2oBkDf4XxI6U3yCB1cq4AufmNXTkl9KqpKbt X-Received: by 2002:a05:6402:3219:b0:4a2:223d:4514 with SMTP id g25-20020a056402321900b004a2223d4514mr7108416eda.8.1675348860339; Thu, 02 Feb 2023 06:41:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675348860; cv=none; d=google.com; s=arc-20160816; b=JA6CP35N5xSYcBMsqk0+1fV63tdqCtiQg+RRKXbszSgEkpQD8cwUwEoIwRFOO51rKt oaaG5TUOx4EdT2RBZGilQrysvidYzwrsEK1wgmfS7JR0S7bwut5bV6SMDfsH24SYEGah V96clEjQ5N9STcU33UpomgSBV+h9OosKvncP132PqUGVEeFRadxsk8RohdvjF9+g49h+ 0/WtbkE5JFjQ5AzFHcD2l+tWKBDIF5jytNzBEjPR59v2KL42BYNwJc2hqe87RhVN5TeF jV6eDjBKwv96y0nJEqWNJhyL1PguItYDFZZ1wzutVLSjlvlHTl6W75/AZnuHa6nNor0f c3bA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=w9YVbgCsA6jXjiCngtb3WKdMb4shRdxAuHTH3z71NIs=; b=QTZm3YNW7jSVUHjb8RHBcxwj3Mm7flYQTVDct119E/0N0kIWR6v8ZYpzF7ZbkXuQmV x9XApvxnuMyfPeRp4vvt3nZLUlHMTzdeyGxefIFHFGdCtybQlSOy/c6dzis4ocU6q4LV vOI2455hohd7zC4RpMu+QCWVdt/pamqkh1impvBocEmOSPQ5u6hKYB53/7nAizZHsDht Ay3evZYLJIIYAcc6PhJDicpHEoXJkmJ0kTsFIy/HPwvCHQ2Axjy8E/+p8PmeQSF687Xh 1ku5oyYpv3DyQVLQPeXRFl03ERZHS3YY/eZEiD/wNZN1cKMCjqvVrMyewTmsEmUFqBhI jC6w== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=bI4+QzpN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id w9-20020aa7d289000000b004a2121f5253si19285164edq.387.2023.02.02.06.40.36; Thu, 02 Feb 2023 06:41:00 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=bI4+QzpN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232474AbjBBOdm (ORCPT + 99 others); Thu, 2 Feb 2023 09:33:42 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45056 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232447AbjBBOd1 (ORCPT ); Thu, 2 Feb 2023 09:33:27 -0500 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17B048394B; Thu, 2 Feb 2023 06:33:15 -0800 (PST) Received: by mail-ej1-x632.google.com with SMTP id mc11so6427181ejb.10; Thu, 02 Feb 2023 06:33:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=w9YVbgCsA6jXjiCngtb3WKdMb4shRdxAuHTH3z71NIs=; b=bI4+QzpNgMb76N2jAaLVJRnwKESrPvVjfoDD900pgrOqxce/HTt6ucaQSiVOSUj9z/ g0c0xptO6xSWyasVsDK9G9CDy52Y76TcK2wxUwMDIshXtTug77o5Gw4SmNxA1XiMtxrJ mCotGxSsaiQHvypbV+4jqzL5gag12DKZNpecA7lQK5zGtIsA0IVJv/5PAA3xHb8BqD26 m46IVZuirRNXxj5V4AtNg9zjSOZb1nqG4qsujgpJdrKPol4+NKQFC+kQgyEBTPe7pPk3 iGaP4UrFf3W/KblNnVZySCoTgc5oEwzfWvPQer+FULhcVz6SRRyOXX1efCxPF35P/dYN CCMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w9YVbgCsA6jXjiCngtb3WKdMb4shRdxAuHTH3z71NIs=; b=1yVxQanbntlaVW/AWy27psZPU6uQGLTYC5JIfbU5Y2zrZwN67oo33uXxYbyFJ1bjZ8 wB3bqxhaG9io42LIZjkq9PbV0k+1nmNdUNh9YrxACRvGybFYyckukKQIGTAy36ZhwkoD xfSZpDbbQ0nFBmtSu8Dv03o1FSaIQnIWhV70dvxd+vZVG8VfHiKaehYCfmg58aUbDO4i 3+1Ir1YOTOF0uKXDcwE0kuZnP5zbWrDoONoVObzEd40ypx+ZjRzvfiWF0AEiHu/qE3+E +erZD736O1XU8TV9i/occc96CEGjbz4KkbKc6sDfqu6WHFvLEUjKSDAxPMvgVIuDZjM/ /W3Q== X-Gm-Message-State: AO0yUKXqZDItHbeZg4iignJ7kHD0UjCyniE8EcLSi0joFSrxun+cv4YM uGyUn7d/8crMz0FMiV52JwljxP+2aCbmow== X-Received: by 2002:a17:907:78d4:b0:878:7a0e:5730 with SMTP id kv20-20020a17090778d400b008787a0e5730mr6187505ejc.56.1675348393539; Thu, 02 Feb 2023 06:33:13 -0800 (PST) Received: from fedora.local.tbs-biometrics.cz (176-74-132-138.netdatacomm.cz. [176.74.132.138]) by smtp.gmail.com with ESMTPSA id h17-20020a1709066d9100b0087856bd9dbbsm11814237ejt.97.2023.02.02.06.33.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Feb 2023 06:33:13 -0800 (PST) From: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= To: linux-kernel@vger.kernel.org Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, gregkh@linuxfoundation.org, martin.petersen@oracle.com, beanhuo@micron.com, arnd@arndb.de, avri.altman@wdc.com, iwona.winiarska@intel.com, fmdefrancesco@gmail.com, dipenp@nvidia.com, ogabbay@kernel.org, bvanassche@acm.org, mathieu.poirier@linaro.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, devicetree@vger.kernel.org, linus.walleij@linaro.org, =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= Subject: [PATCHv2 2/4] wiegand: add Wiegand bus driver Date: Thu, 2 Feb 2023 15:33:03 +0100 Message-Id: <20230202143305.21789-3-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230202143305.21789-1-m.zatovic1@gmail.com> References: <20230202143305.21789-1-m.zatovic1@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756730606137955006?= X-GMAIL-MSGID: =?utf-8?q?1756730606137955006?= Add a bus driver for Wiegand protocol. The bus driver handles Wiegand controller and Wiegand device managemement and driver matching. The bus driver defines the structures for Wiegand controllers and Wiegand devices. Wiegand controller structure represents a master and contains attributes such as the payload_len for configuring the size of a single Wiegand message in bits. It also stores the controller attributes defined in the devicetree. Each Wiegand controller should be associated with one Wiegand device, as Wiegand is typically a point-to-point bus. Signed-off-by: Martin Zaťovič --- MAINTAINERS | 2 + drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/wiegand/Kconfig | 20 ++ drivers/wiegand/Makefile | 1 + drivers/wiegand/wiegand.c | 543 ++++++++++++++++++++++++++++++++++++++ include/linux/wiegand.h | 177 +++++++++++++ 7 files changed, 746 insertions(+) create mode 100644 drivers/wiegand/Kconfig create mode 100644 drivers/wiegand/Makefile create mode 100644 drivers/wiegand/wiegand.c create mode 100644 include/linux/wiegand.h diff --git a/MAINTAINERS b/MAINTAINERS index db9624d93af0..8119d12dac41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22432,6 +22432,8 @@ WIEGAND BUS DRIVER M: Martin Zaťovič S: Maintained F: Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml +F: drivers/wiegand/wiegand.c +F: include/linux/wiegand.h WILOCITY WIL6210 WIRELESS DRIVER L: linux-wireless@vger.kernel.org diff --git a/drivers/Kconfig b/drivers/Kconfig index 968bd0a6fd78..bedc5a9fecba 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -67,6 +67,8 @@ source "drivers/spi/Kconfig" source "drivers/spmi/Kconfig" +source "drivers/wiegand/Kconfig" + source "drivers/hsi/Kconfig" source "drivers/pps/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index bdf1c66141c9..c5b613e2045a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -146,6 +146,7 @@ obj-$(CONFIG_VHOST_RING) += vhost/ obj-$(CONFIG_VHOST_IOTLB) += vhost/ obj-$(CONFIG_VHOST) += vhost/ obj-$(CONFIG_VLYNQ) += vlynq/ +obj-$(CONFIG_WIEGAND) += wiegand/ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_STAGING) += staging/ diff --git a/drivers/wiegand/Kconfig b/drivers/wiegand/Kconfig new file mode 100644 index 000000000000..fc99575bc3cc --- /dev/null +++ b/drivers/wiegand/Kconfig @@ -0,0 +1,20 @@ +config WIEGAND + tristate "Wiegand Bus driver" + help + The "Wiegand Interface" is an asynchronous low-level protocol + or wiring standard. It is typically used for point-to-point + communication. The data length of Wiegand messages is not defined, + so the devices usually default to 26, 36 or 37 bits per message. + The throughput of Wiegand depends on the selected pulse length and + the intervals between pulses, in comparison to other busses it + is generally rather slow. + + Despite its higher age, Wiegand remains widely used in access + control systems to connect a card swipe mechanism. Such mechanisms + utilize the Wiegand effect to transfer data from the card to + the reader. + + Wiegand uses two wires to transmit the data D0 and D1. Both lines + are initially pulled up. When a bit of value 0 is being transmitted, + the D0 line is pulled down. Similarly, when a bit of value 1 is being + transmitted, the D1 line is pulled down. diff --git a/drivers/wiegand/Makefile b/drivers/wiegand/Makefile new file mode 100644 index 000000000000..d17ecb722c6e --- /dev/null +++ b/drivers/wiegand/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_WIEGAND) += wiegand.o diff --git a/drivers/wiegand/wiegand.c b/drivers/wiegand/wiegand.c new file mode 100644 index 000000000000..1147195fc256 --- /dev/null +++ b/drivers/wiegand/wiegand.c @@ -0,0 +1,543 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct bus_type wiegand_bus_type; +static DEFINE_IDR(wiegand_controller_idr); + +static void devm_wiegand_release_controller(struct device *dev, void *ctlr) +{ + wiegand_controller_put(*(struct wiegand_controller **)ctlr); +} + +static void wiegand_controller_release(struct device *dev) +{ + struct wiegand_controller *ctlr; + + ctlr = container_of(dev, struct wiegand_controller, dev); + kfree(ctlr); +} + +static struct class wiegand_controller_class = { + .name = "wiegand_master", + .owner = THIS_MODULE, + .dev_release = wiegand_controller_release, +}; + +static DEFINE_MUTEX(board_lock); + +struct wiegand_controller *__wiegand_alloc_controller(struct device *dev, + unsigned int size, bool slave) +{ + struct wiegand_controller *ctlr; + size_t ctlr_size = ALIGN(sizeof(*ctlr), dma_get_cache_alignment()); + + if (!dev) + return NULL; + + ctlr = kzalloc(size + ctlr_size, GFP_KERNEL); + if (!ctlr) + return NULL; + + device_initialize(&ctlr->dev); + ctlr->bus_num = -1; + ctlr->slave = slave; + ctlr->dev.class = &wiegand_controller_class; + ctlr->dev.parent = dev; + wiegand_controller_set_devdata(ctlr, (void *)ctlr + ctlr_size); + + return ctlr; +} +EXPORT_SYMBOL_GPL(__wiegand_alloc_controller); + +struct wiegand_controller *__devm_wiegand_alloc_controller(struct device *dev, + unsigned int size, + bool slave) +{ + struct wiegand_controller **ptr, *ctlr; + + ptr = devres_alloc(devm_wiegand_release_controller, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return NULL; + + ctlr = __wiegand_alloc_controller(dev, size, slave); + if (ctlr) { + ctlr->devm_allocated = true; + *ptr = ctlr; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ctlr; +} +EXPORT_SYMBOL_GPL(__devm_wiegand_alloc_controller); + +static int wiegand_controller_check_ops(struct wiegand_controller *ctlr) +{ + if (!ctlr->transfer_message) + return -EINVAL; + return 0; +} + +static struct wiegand_device *of_register_wiegand_device( + struct wiegand_controller *ctlr, + struct device_node *nc) +{ + struct wiegand_device *wiegand; + int rc; + + wiegand = wiegand_alloc_device(ctlr); + if (!wiegand) { + dev_err(&ctlr->dev, "wiegad_device alloc error for %pOF\n", nc); + rc = -ENOMEM; + goto err_out; + } + + rc = of_modalias_node(nc, wiegand->modalias, sizeof(wiegand->modalias)); + if (rc < 0) { + dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc); + goto err_out; + } + + of_node_get(nc); + wiegand->dev.of_node = nc; + wiegand->dev.fwnode = of_fwnode_handle(nc); + + rc = wiegand_add_device(wiegand); + if (rc) { + dev_err(&ctlr->dev, "wiegand_device register error %pOF\n", nc); + goto err_of_node_put; + } + + /* check if more devices are connected to the bus */ + if (ctlr->device_count > 1) + dev_warn(&ctlr->dev, "Wiegand is a point-to-point bus, it is advised to only connect one device per Wiegand bus. The devices may not communicate using the same pulse length, format or else.\n"); + + return wiegand; + +err_of_node_put: + of_node_put(nc); +err_out: + wiegand_dev_put(wiegand); + return ERR_PTR(rc); +} + +static void of_register_wiegand_devices(struct wiegand_controller *ctlr) +{ + struct wiegand_device *wiegand; + struct device_node *nc; + + if (!ctlr->dev.of_node) + return; + + for_each_available_child_of_node(ctlr->dev.of_node, nc) { + if (of_node_test_and_set_flag(nc, OF_POPULATED)) + continue; + wiegand = of_register_wiegand_device(ctlr, nc); + if (IS_ERR(wiegand)) { + dev_warn(&ctlr->dev, + "Failed to create wiegand device for %pOF\n", + nc); + of_node_clear_flag(nc, OF_POPULATED); + } + } +} + +/* + * Controllers that do not have a devicetree entry need to initialize the + * following struct wiegand_controller attributes: pulse_len, interval_len and + * frame_gap. + */ +int wiegand_register_controller(struct wiegand_controller *ctlr) +{ + struct device *dev = ctlr->dev.parent; + int status, id, first_dynamic; + + if (!dev) + return -ENODEV; + + status = wiegand_controller_check_ops(ctlr); + if (status) + return status; + + if (ctlr->dev.of_node) { + id = of_alias_get_id(ctlr->dev.of_node, "wiegand"); + if (id > 0) { + ctlr->bus_num = id; + mutex_lock(&board_lock); + id = idr_alloc(&wiegand_controller_idr, ctlr, + ctlr->bus_num, + ctlr->bus_num + 1, + GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr")) + return id == -ENOSPC ? -EBUSY : id; + } + device_property_read_u32(&ctlr->dev, "pulse-len-us", + &ctlr->pulse_len); + device_property_read_u32(&ctlr->dev, "interval-len-us", + &ctlr->interval_len); + device_property_read_u32(&ctlr->dev, "frame-gap-us", + &ctlr->frame_gap); + } + if (ctlr->bus_num < 0) { + first_dynamic = of_alias_get_highest_id("wiegand"); + if (first_dynamic < 0) + first_dynamic = 0; + else + first_dynamic++; + + mutex_lock(&board_lock); + id = idr_alloc(&wiegand_controller_idr, ctlr, first_dynamic, + 0, GFP_KERNEL); + mutex_unlock(&board_lock); + if (WARN(id < 0, "couldn't get idr\n")) + return id; + ctlr->bus_num = id; + } + + if (ctlr->pulse_len == 0) + dev_warn(&ctlr->dev, "pulse_len is not initialized\n"); + if (ctlr->interval_len == 0) + dev_warn(&ctlr->dev, "interval_len is not initialized\n"); + if (ctlr->frame_gap == 0) + dev_warn(&ctlr->dev, "frame_gap is not initialized\n"); + + dev_set_name(&ctlr->dev, "wiegand%u", ctlr->bus_num); + ctlr->device_count = 0; + + status = device_add(&ctlr->dev); + if (status < 0) + goto free_bus_id; + + of_register_wiegand_devices(ctlr); + + return status; + +free_bus_id: + mutex_lock(&board_lock); + idr_remove(&wiegand_controller_idr, ctlr->bus_num); + mutex_unlock(&board_lock); + return status; +} + +static int __unregister(struct device *dev, void *null) +{ + wiegand_unregister_device(to_wiegand_device(dev)); + return 0; +} + +void wiegand_unregister_controller(struct wiegand_controller *ctlr) +{ + struct wiegand_controller *found; + int id = ctlr->bus_num; + + device_for_each_child(&ctlr->dev, NULL, __unregister); + found = idr_find(&wiegand_controller_idr, id); + device_del(&ctlr->dev); + + mutex_lock(&board_lock); + if (found == ctlr) + idr_remove(&wiegand_controller_idr, id); + mutex_unlock(&board_lock); + + if (!ctlr->devm_allocated) + put_device(&ctlr->dev); +} +EXPORT_SYMBOL_GPL(wiegand_unregister_controller); + +static void devm_wiegand_unregister(struct device *dev, void *res) +{ + wiegand_unregister_controller(*(struct wiegand_controller **)res); +} + +int devm_wiegand_register_controller(struct device *dev, + struct wiegand_controller *ctlr) +{ + struct wiegand_controller **ptr; + int ret; + + ptr = devres_alloc(devm_wiegand_unregister, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = wiegand_register_controller(ctlr); + if (!ret) { + *ptr = ctlr; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_wiegand_register_controller); + +static int __wiegand_master_match(struct device *dev, const void *data) +{ + struct wiegand_master *master; + const u16 *bus_num = data; + + master = container_of(dev, struct wiegand_master, dev); + return master->bus_num == *bus_num; +} + +struct wiegand_master *wiegand_busnum_to_master(u16 bus_num) +{ + struct device *dev; + struct wiegand_master *master = NULL; + + dev = class_find_device(&wiegand_controller_class, NULL, &bus_num, + __wiegand_master_match); + if (dev) + master = container_of(dev, struct wiegand_master, dev); + + return master; +} +EXPORT_SYMBOL_GPL(wiegand_busnum_to_master); + +/* Device section */ + +static void wieganddev_release(struct device *dev) +{ + struct wiegand_device *wiegand = to_wiegand_device(dev); + + wiegand_controller_put(wiegand->controller); + kfree(wiegand); +} + +struct wiegand_device *wiegand_alloc_device(struct wiegand_controller *ctlr) +{ + struct wiegand_device *wiegand; + + if (!wiegand_controller_get(ctlr)) + return NULL; + + wiegand = kzalloc(sizeof(*wiegand), GFP_KERNEL); + if (!wiegand) { + wiegand_controller_put(ctlr); + return NULL; + } + + wiegand->controller = ctlr; + wiegand->dev.parent = &ctlr->dev; + wiegand->dev.bus = &wiegand_bus_type; + wiegand->dev.release = wieganddev_release; + + device_initialize(&wiegand->dev); + return wiegand; +} +EXPORT_SYMBOL_GPL(wiegand_alloc_device); + +static void wiegand_cleanup(struct wiegand_device *wiegand) +{ + if (wiegand->controller->cleanup) + wiegand->controller->cleanup(wiegand); +} + +static int __wiegand_add_device(struct wiegand_device *wiegand) +{ + struct wiegand_controller *ctlr = wiegand->controller; + struct device *dev = ctlr->dev.parent; + int status; + + status = wiegand_setup(wiegand); + if (status < 0) { + dev_err(dev, "can't setup %s, status %d\n", + dev_name(&wiegand->dev), status); + return status; + } + + status = device_add(&wiegand->dev); + if (status < 0) { + dev_err(dev, "can't add %s, status %d\n", + dev_name(&wiegand->dev), status); + wiegand_cleanup(wiegand); + } else { + dev_dbg(dev, "registered child %s\n", dev_name(&wiegand->dev)); + } + + return status; +} + +static void wiegand_dev_set_name(struct wiegand_device *wiegand, u8 id) +{ + dev_set_name(&wiegand->dev, "%s.%u", + dev_name(&wiegand->controller->dev), id); +} + +int wiegand_add_device(struct wiegand_device *wiegand) +{ + struct wiegand_controller *ctlr = wiegand->controller; + int status; + + wiegand_dev_set_name(wiegand, ctlr->device_count); + + status = __wiegand_add_device(wiegand); + if (!status) { + ctlr->device_count++; + wiegand->id = wiegand->controller->device_count; + } + + return status; +} + +int wiegand_setup(struct wiegand_device *wiegand) +{ + int status = 0; + + if (wiegand->controller->setup) { + status = wiegand->controller->setup(wiegand); + if (status) { + dev_err(&wiegand->controller->dev, + "Failed to setup device: %d\n", + status); + return status; + } + } + + return status; +} +EXPORT_SYMBOL_GPL(wiegand_setup); + +void wiegand_unregister_device(struct wiegand_device *wiegand) +{ + if (!wiegand) + return; + + if (wiegand->dev.of_node) { + of_node_clear_flag(wiegand->dev.of_node, OF_POPULATED); + of_node_put(wiegand->dev.of_node); + } + device_del(&wiegand->dev); + wiegand_cleanup(wiegand); + put_device(&wiegand->dev); +} +EXPORT_SYMBOL_GPL(wiegand_unregister_device); + +int wiegand_send_message(struct wiegand_device *wiegand, u8 *message, u8 bitlen) +{ + struct wiegand_master *master = wiegand->controller; + + if (message == NULL || message == 0) + return -EINVAL; + + if (master->transfer_message) + master->transfer_message(wiegand, message, bitlen); + + return 0; +} +EXPORT_SYMBOL_GPL(wiegand_send_message); + +static int wiegand_match_device(struct device *dev, struct device_driver *drv) +{ + const struct wiegand_device *wiegand = to_wiegand_device(dev); + + if (of_driver_match_device(dev, drv)) + return 1; + + return strcmp(wiegand->modalias, drv->name) == 0; +} + +static int wiegand_probe(struct device *dev) +{ + struct wiegand_device *wiegand = to_wiegand_device(dev); + const struct wiegand_driver *wdrv = to_wiegand_driver(dev->driver); + int ret = 0; + + if (wdrv->probe) + ret = wdrv->probe(wiegand); + + return ret; +} + +static void wiegand_remove(struct device *dev) +{ + const struct wiegand_driver *wdrv = to_wiegand_driver(dev->driver); + + if (wdrv->remove) + wdrv->remove(to_wiegand_device(dev)); +} + +static struct bus_type wiegand_bus_type = { + .name = "wiegand", + .match = wiegand_match_device, + .probe = wiegand_probe, + .remove = wiegand_remove, +}; + +int __wiegand_register_driver(struct module *owner, struct wiegand_driver *wdrv) +{ + wdrv->driver.owner = owner; + wdrv->driver.bus = &wiegand_bus_type; + + if (wdrv->driver.of_match_table) { + const struct of_device_id *of_id; + + for (of_id = wdrv->driver.of_match_table; of_id->compatible[0]; + of_id++) { + const char *of_name; + + /* remove vendor prefix */ + of_name = strnchr(of_id->compatible, + sizeof(of_id->compatible), ','); + if (of_name) + of_name++; + else + of_name = of_id->compatible; + + if (strcmp(wdrv->driver.name, of_name) == 0) + continue; + + pr_warn("Wiegand driver %s has no device_id for %s\n", + wdrv->driver.name, of_id->compatible); + } + } + + return driver_register(&wdrv->driver); +} +EXPORT_SYMBOL_GPL(__wiegand_register_driver); + +static int __init wiegand_init(void) +{ + int ret; + + ret = bus_register(&wiegand_bus_type); + if (ret < 0) { + pr_err("Wiegand bus registration failed: %d\n", ret); + goto err0; + } + + ret = class_register(&wiegand_controller_class); + if (ret < 0) + goto err1; + + return 0; + +err1: + bus_unregister(&wiegand_bus_type); +err0: + return ret; +} + +static void __exit wiegand_exit(void) +{ + bus_unregister(&wiegand_bus_type); + class_unregister(&wiegand_controller_class); +} +postcore_initcall_sync(wiegand_init); +module_exit(wiegand_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Wiegand bus driver"); +MODULE_AUTHOR("Martin Zaťovič "); diff --git a/include/linux/wiegand.h b/include/linux/wiegand.h new file mode 100644 index 000000000000..dc733af464c4 --- /dev/null +++ b/include/linux/wiegand.h @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef H_LINUX_INCLUDE_LINUX_WIEGAND_H +#define H_LINUX_INCLUDE_LINUX_WIEGAND_H + +#include +#include +#include + +#define WIEGAND_NAME_SIZE 32 + +extern struct bus_type wiegand_type; + +/** + * struct wiegand_device - Wiegand listener device + * @dev - drivers structure of the device + * @id - unique device id + * @controller - Wiegand controller associated with the device + * @modalias - Name of the driver to use with this device, or its alias. + */ +struct wiegand_device { + struct device dev; + u8 id; + struct wiegand_controller *controller; + char modalias[WIEGAND_NAME_SIZE]; +}; + +/** + * struct wiegand_controller - Wiegand master or slave interface + * @dev - Device interface of the controller + * @list - Link with the global wiegand_controller list + * @bus_num - Board-specific identifier for Wiegand controller + * @pulse_len: length of the low pulse in usec; defaults to 50us + * @interval_len: length of a whole bit (both the pulse and the high phase) in + * usec; defaults to 2000us + * @frame_gap: length of the last bit of a frame (both the pulse and the high + * phase) in usec; defaults to interval_len + * device_count - Counter of devices connected to the same Wiegand + * bus(controller). + * devm_allocated - Whether the allocation of this struct is devres-managed + * slave - Whether the controller is a slave(receives data). + * transfer_message - Send a message on the bus. + * setup - Setup a device. + * cleanup - Cleanup after a device. + */ +struct wiegand_controller { + struct device dev; + struct list_head list; + + s16 bus_num; + + u32 pulse_len; + u32 interval_len; + u32 frame_gap; + + u32 payload_len; + + u8 device_count; + + bool devm_allocated; + bool slave; + + int (*transfer_message)(struct wiegand_device *dev, u8 *message, + u8 bitlen); + + int (*setup)(struct wiegand_device *wiegand); + void (*cleanup)(struct wiegand_device *wiegand); +}; + +struct wiegand_driver { + const struct wiegand_device_id *id_table; + int (*probe)(struct wiegand_device *wiegand); + void (*remove)(struct wiegand_device *wiegand); + struct device_driver driver; +}; + +/* Wiegand controller section */ + +#define wiegand_master wiegand_controller +extern struct wiegand_controller *__wiegand_alloc_controller( + struct device *host, + unsigned int size, + bool slave); + +struct wiegand_controller *__devm_wiegand_alloc_controller(struct device *dev, + unsigned int size, + bool slave); +struct wiegand_controller *__wiegand_alloc_controller(struct device *dev, + unsigned int size, + bool slave); +static inline struct wiegand_controller *devm_wiegand_alloc_master( + struct device *dev, + unsigned int size) +{ + return __devm_wiegand_alloc_controller(dev, size, false); +} +extern int wiegand_register_controller(struct wiegand_controller *ctlr); +extern int devm_wiegand_register_controller(struct device *dev, + struct wiegand_controller *ctlr); +#define wiegand_register_master(_ctlr) wiegand_register_controller(_ctlr) +#define devm_wiegand_register_master(_dev, _ctlr) \ + devm_wiegand_register_controller(_dev, _ctlr) +extern void wiegand_unregister_controller(struct wiegand_controller *ctlr); +#define wiegand_unregister_master(_ctlr) wiegand_unregister_controller(_ctlr) +extern struct wiegand_master *wiegand_busnum_to_master(u16 bus_num); + +static inline void *wiegand_controller_get_devdata( + struct wiegand_controller *ctlr) +{ + return dev_get_drvdata(&ctlr->dev); +} + +static inline void wiegand_controller_set_devdata( + struct wiegand_controller *ctlr, + void *data) +{ + dev_set_drvdata(&ctlr->dev, data); +} + +#define wiegand_master_get_devdata(_ctlr) \ + wiegand_controller_get_devdata(_ctlr) +#define wiegand_master_set_devdata(_ctlr, _data) \ + wiegand_controller_set_devdata(_ctlr, _data) + +static inline struct wiegand_controller *wiegand_controller_get( + struct wiegand_controller *ctlr) +{ + if (!ctlr || !get_device(&ctlr->dev)) + return NULL; + return ctlr; +} + +static inline void wiegand_controller_put(struct wiegand_controller *ctlr) +{ + if (ctlr) + put_device(&ctlr->dev); +} + +/* Wiegand device section */ + +extern struct wiegand_device *wiegand_alloc_device( + struct wiegand_controller *ctlr); +extern int wiegand_add_device(struct wiegand_device *wiegand); +extern int wiegand_setup(struct wiegand_device *wiegand); +extern void wiegand_unregister_device(struct wiegand_device *wiegand); + +extern int wiegand_send_message(struct wiegand_device *wiegand, u8 *message, + u8 bitlen); + +static inline struct wiegand_device *to_wiegand_device(struct device *dev) +{ + return dev ? container_of(dev, struct wiegand_device, dev) : NULL; +} +static inline void wiegand_dev_put(struct wiegand_device *wiegand) +{ + if (wiegand) + put_device(&wiegand->dev); +} + +/* Wiegand driver section */ + +static inline struct wiegand_driver *to_wiegand_driver(struct device_driver *drv) +{ + return drv ? container_of(drv, struct wiegand_driver, driver) : NULL; +} +extern int __wiegand_register_driver(struct module *owner, + struct wiegand_driver *wdrv); +#define wiegand_register_driver(driver) \ + __wiegand_register_driver(THIS_MODULE, driver) + +static inline void wiegand_unregister_driver(struct wiegand_driver *wdrv) +{ + if (wdrv) + driver_unregister(&wdrv->driver); +} + +#endif /* H_LINUX_INCLUDE_LINUX_WIEGAND_H */ From patchwork Thu Feb 2 14:33:04 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= X-Patchwork-Id: 51960 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp277746wrn; Thu, 2 Feb 2023 06:41:50 -0800 (PST) X-Google-Smtp-Source: AK7set9L1se3TydwGs4K2Z7nR0loBsp7UpbizW6EWCTpD94v1fjk9XN1/lQBlHP3U7+7yfXcE1YS X-Received: by 2002:a17:906:b147:b0:7c9:6e0e:1427 with SMTP id bt7-20020a170906b14700b007c96e0e1427mr5712176ejb.6.1675348910270; Thu, 02 Feb 2023 06:41:50 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675348910; cv=none; d=google.com; s=arc-20160816; b=v3ppS/JtiNy8+IAQ3mGqdYiBze2ezeDUhaCW1WyIBoxCyXxS7PGLX0RR8xrjFqnM0N yJkbjc2shQJLx35Uk9uKDcnvYLfgyl1ybfKVGAtae7S/iCQiOvJBGbqhadLxM47xlzw2 dulAc7VIfykTzaT0Oy5W6x3NZEentiPgwk71ukwCZOPg7dAa06ecm1dOzkJTPFyj44fA S7qjRTGpZPrGS9dR/VImG76xV2IKs4DsWvuGIfCb5JVJS1Xoci4+LOioVaJ2CSnklMnh HeJz776QER1J6dpfofkWZvEhDPCWEnIzFhNyWA+fEOW1MRAdZjLpnps64fjIwI6HM//c yTaA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=hYfcce3tKsjP0K5Vg/OUHjCofLEX8tvrmEMZwYBrXQ0=; b=EqFnjUa1dEe7PYoKSX8KhkiIdK7oSr9fXmRa+Cn8rj2vByL7ZUU/O7vth/qOtj9SCV HX64T4df1wBr0pbMBbVRVxXrPT21bv+ugY+Y0PTElV9txKwj6xiZj6oUvekJjVf4n4Vd ZZkAXzx/wjM9GTj+sSGEbe7bpC/ezJ+uJRroOEspnJ6DS77Caho6+dfU2MWMaJ1TvxaX dbAOFHr5HQgHVGmH+ZnUKLH+4qb6l2r9KMkvFY3VMO+whihbAiLEDe4STewB2Cgi6SwJ PyGEBK2RcvLKwlKp4laliXldfDZeT2HC0snbFU2x4zQrXL7by8lCxpj0GEAvXsCNMInr t9dg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=gEutbN+M; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id sh39-20020a1709076ea700b0087787ae09e7si35282671ejc.210.2023.02.02.06.41.25; Thu, 02 Feb 2023 06:41:50 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=gEutbN+M; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232539AbjBBOdt (ORCPT + 99 others); Thu, 2 Feb 2023 09:33:49 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232503AbjBBOdc (ORCPT ); Thu, 2 Feb 2023 09:33:32 -0500 Received: from mail-ej1-x633.google.com (mail-ej1-x633.google.com [IPv6:2a00:1450:4864:20::633]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 177896F210; Thu, 2 Feb 2023 06:33:17 -0800 (PST) Received: by mail-ej1-x633.google.com with SMTP id dr8so6401225ejc.12; Thu, 02 Feb 2023 06:33:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hYfcce3tKsjP0K5Vg/OUHjCofLEX8tvrmEMZwYBrXQ0=; b=gEutbN+MF4m4qaELiNNglwGbzC1VylJ47LcnFiIK5ddNzC5op+2YwKTH9PwoxRksf+ 35HIdaRfNi83DlZAzs1C4m2wPaF4iXYgCmkA0CU3scVDQkvsT6SskgvsHmvLoeewOYFk EEy33QrwSqhz3ytvc1UN+5CR8Xzr7cIgrwq8NhUHXFkGOjwcIP2nKPXcfXZ8Cgxc3GTW rRLcrjcGlM79R8ji69ldJpaqg/im4dkPiKknODwvqspZrbSeae7fMgm5qUy1l5zlbkLS auk5+XBWO5eyHhVroYIhT7y15DpJvd+PhMX4KhD43rvEPagoy9ugnEjr4Zl810rrJ3bb kwZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hYfcce3tKsjP0K5Vg/OUHjCofLEX8tvrmEMZwYBrXQ0=; b=sDr3MiKGOQlcf4u1UiGjUEnUxNdO49UIVCW5JtGI1XaWyBZpOOIjC7JeiMpKLZFT2L PerVV+trnVo/qeG114LvvsEjpG81J+vmPmlfHa3x2XaYbdGcVRqyHmWfnWejbxAHKGZd LnymVwHDt/ouSMaHh09xWpuzoh9EG72alMykZ2QI2oU9KN2tyruhHUDv3URgA1q/K43h t0F9jEAiRP78J9OcRYOjXgGkvSjNOvqsBeUDQ7+5bFTP8xi/Qr6B2DBG90eUuoyuFnzE RWUlPCO1DBXnI+yWKwXjStKIp2g49nBPBW8PMTLP7Km45aqVVUEeSAGPk+usm8qUEmgC nzzA== X-Gm-Message-State: AO0yUKW2zY5cH2EKosfQZHdBKxLvUt2FYdGETkTkIs+F15ZyTzRMJNf/ Gp3MLrVBKfTzqrPMCQtjprICR/8XLAEUxA== X-Received: by 2002:a17:906:f913:b0:878:711f:f3d0 with SMTP id lc19-20020a170906f91300b00878711ff3d0mr5545741ejb.4.1675348395498; Thu, 02 Feb 2023 06:33:15 -0800 (PST) Received: from fedora.local.tbs-biometrics.cz (176-74-132-138.netdatacomm.cz. [176.74.132.138]) by smtp.gmail.com with ESMTPSA id h17-20020a1709066d9100b0087856bd9dbbsm11814237ejt.97.2023.02.02.06.33.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Feb 2023 06:33:15 -0800 (PST) From: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= To: linux-kernel@vger.kernel.org Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, gregkh@linuxfoundation.org, martin.petersen@oracle.com, beanhuo@micron.com, arnd@arndb.de, avri.altman@wdc.com, iwona.winiarska@intel.com, fmdefrancesco@gmail.com, dipenp@nvidia.com, ogabbay@kernel.org, bvanassche@acm.org, mathieu.poirier@linaro.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, devicetree@vger.kernel.org, linus.walleij@linaro.org, =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= Subject: [PATCHv2 3/4] dt-bindings: wiegand: add GPIO bitbanged Wiegand documentation Date: Thu, 2 Feb 2023 15:33:04 +0100 Message-Id: <20230202143305.21789-4-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230202143305.21789-1-m.zatovic1@gmail.com> References: <20230202143305.21789-1-m.zatovic1@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756730658803732406?= X-GMAIL-MSGID: =?utf-8?q?1756730658803732406?= GPIO bitbanged Wiegand controller requires definitions of GPIO lines to be used on top of the common Wiegand properties. Wiegand utilizes two such lines - D0(low data line) and D1(high data line). Signed-off-by: Martin Zaťovič --- .../bindings/wiegand/wiegand-gpio.yaml | 51 +++++++++++++++++++ MAINTAINERS | 5 ++ 2 files changed, 56 insertions(+) create mode 100644 Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml diff --git a/Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml b/Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml new file mode 100644 index 000000000000..3af0b7e04b3a --- /dev/null +++ b/Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/wiegand/wiegand-gpio.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GPIO bitbanged Wiegand interface devicetree bindings + +maintainers: + - Martin Zaťovič + +description: + This represents the GPIO lines used for bit-banged Wiegand on dedicated GPIO + lines. + +allOf: + - $ref: "/schemas/wiegand/wiegand-controller.yaml#" + +properties: + compatible: + const: wiegand-gpio + + data-hi-gpios: + description: GPIO used as Wiegands data-hi line. + maxItems: 1 + + data-lo-gpios: + description: GPIO used as Wiegands data-lo line. + maxItems: 1 + +required: + - compatible + - data-hi-gpios + - data-lo-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + wiegand@f00 { + compatible = "wiegand-gpio"; + pulse-len-us = <50>; + interval-len-us = <2000>; + frame-gap-us = <2000>; + data-lo-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + data-hi-gpios = <&gpio2 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>; + + /* devices */ + }; diff --git a/MAINTAINERS b/MAINTAINERS index 8119d12dac41..54d61d95a1ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22435,6 +22435,11 @@ F: Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml F: drivers/wiegand/wiegand.c F: include/linux/wiegand.h +WIEGAND GPIO BITBANG DRIVER +M: Martin Zaťovič +S: Maintained +F: Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml + WILOCITY WIL6210 WIRELESS DRIVER L: linux-wireless@vger.kernel.org S: Orphan From patchwork Thu Feb 2 14:33:05 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= X-Patchwork-Id: 51961 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp280391wrn; Thu, 2 Feb 2023 06:47:05 -0800 (PST) X-Google-Smtp-Source: AK7set+O7XGIfh/yPqYgG0xCT9TaCuxnralWJD/cqyb7AqWdLue06jPKwzSztN8jwxp3Xvt73zbc X-Received: by 2002:a17:90b:4d05:b0:22c:f74:9415 with SMTP id mw5-20020a17090b4d0500b0022c0f749415mr6944193pjb.36.1675349224849; Thu, 02 Feb 2023 06:47:04 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675349224; cv=none; d=google.com; s=arc-20160816; b=gDSV7eic0LDbnhkEdXW5FKa6fnw9YCTLdE/P1KwL21d8PYn0GfXk4EjzKy1X3tOhXL 9+CWdH3/qdTZGL+pVQ919x54FI1MDIr2V98PCTaCFSiZgkbc2b6WSPM3Rdw7fZgguQXc CIcPAFfwINNhJ2YVTuHcs3GrcC4vS0gIT8s7sfPpyQ67ZCcRiBEYC2lPKFZTRAcGiG7W /fKQk5BMRoHavQaqbg/Devs9yW+qT+sS/ZHbCzHYGzLK7rw/lh2gGdHUyEz/fAiJx/X/ o/NWbILaoc/7R3jI4cbXU/wAsSKsDzJsoxqCLGwChmps+kwTZXgiKLW6WHEJyd3qbc33 +YSw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=BouysRvMXXKpWc/jTXsO5Cksblbk/hdxbGtkII6MiNk=; b=eudWojqEIu8tItk1w1wRPSJcLmM/LzKQV6oc+OjYSHGfZGSgFYH6+x3pvAi40n61Zg 18q2bUSyKWYSk1GOahYGaPpImDOH/yQ/7HNXhArzUsgW0dw0gynwWO4VhV9JUS4P58OZ /2+a6+BL8m6H9LXsKbYI9qtJPHEy6B8H5XbQlQz91ZLSuxG+ilY15vVyZ6BVLLk6b2uA GESV1ggqqERocno69F+5cYnH3jTUCW8aFuPKGhzZex1NXmnafxvN/VpccfKmtKesCS4J 4u2qmCli/vpkHkAPwdEBrrTlijMkrtaPxtDUD/NQ8jkZxYx6fcQdtEji56V+moAQNXDf oeHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=mektjHVN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ca11-20020a17090af30b00b0022948b53969si3939441pjb.142.2023.02.02.06.46.50; Thu, 02 Feb 2023 06:47:04 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=mektjHVN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232431AbjBBOdy (ORCPT + 99 others); Thu, 2 Feb 2023 09:33:54 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45388 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232504AbjBBOdd (ORCPT ); Thu, 2 Feb 2023 09:33:33 -0500 Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CDF358B319; Thu, 2 Feb 2023 06:33:19 -0800 (PST) Received: by mail-ej1-x62f.google.com with SMTP id m2so6462561ejb.8; Thu, 02 Feb 2023 06:33:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=BouysRvMXXKpWc/jTXsO5Cksblbk/hdxbGtkII6MiNk=; b=mektjHVNBYl0DwnmNo5L6NA+g2gJr+d9bGqTjsIdjKxkY6IfsABzvQeLSvUFNZdflo 4c8dRrV7++zTi11W3jhbqo1h24Rn3Qk0w+mUA/2IozZ5RxBjCqr4JMHMdpUiKuFbdyHY qyF+eNCxyG4TgruxWQHTy7BlqunGeUQlaGck7PkyDxVfNtdjsnlUdkRHzlc0XaShlwPw F7dKZX4UFH/BLAj+nZMmo29pYSKVwRA/ZhSIaLDso4WoeVNiQfo6BqlEAVWWw5o4JUMR TX6kO7D7V0mtiN6Z6e/pI4Ns/vf4Ea6W5IChy3KQP8vnBt+Lyg5ctQ5BcfUng5YfHyMl cOYw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=BouysRvMXXKpWc/jTXsO5Cksblbk/hdxbGtkII6MiNk=; b=jq9lmVu1ZUaEki+S0LVd+d65Tluu0H8srYtN2a0yn5eL1B3x45qYP3h11svISTq3/2 B5A2S0/cIN5yrQtz0Wes3iWvV6bdbLu4kgoULfMMGkF9PS46CDRvi+cCsKhJpkWHSO1x /NN4mOzQ32qOWnsjNcrGQAqi4T5vfi6CSvxnU88ZZt7naG2RLUYQuCVMSRefeFA8gq4G TysGp2xSZOtCAxPUSO8+SaBZBq6add2O0Ague+gs2JwG8ffrHhewzGf7UHoLHq2+Ljo6 CrRrK+cBEKTF2TiJxJFThpH8sBsIedC2hMfpxiJ4SgCKTUweliSx8RQgjMXFJiBxYK1I X0oQ== X-Gm-Message-State: AO0yUKXrKQIMQFv6KXyS5rSL0bB9o/kYERGMW6fT4uGdwKogYv00asLr iy1vIZR62x1ZuAl8Y8wxu9mAdych3cmroA== X-Received: by 2002:a17:907:6f1b:b0:889:b6ae:75fe with SMTP id sy27-20020a1709076f1b00b00889b6ae75femr6250009ejc.61.1675348398308; Thu, 02 Feb 2023 06:33:18 -0800 (PST) Received: from fedora.local.tbs-biometrics.cz (176-74-132-138.netdatacomm.cz. [176.74.132.138]) by smtp.gmail.com with ESMTPSA id h17-20020a1709066d9100b0087856bd9dbbsm11814237ejt.97.2023.02.02.06.33.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 02 Feb 2023 06:33:17 -0800 (PST) From: =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= To: linux-kernel@vger.kernel.org Cc: robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org, gregkh@linuxfoundation.org, martin.petersen@oracle.com, beanhuo@micron.com, arnd@arndb.de, avri.altman@wdc.com, iwona.winiarska@intel.com, fmdefrancesco@gmail.com, dipenp@nvidia.com, ogabbay@kernel.org, bvanassche@acm.org, mathieu.poirier@linaro.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, devicetree@vger.kernel.org, linus.walleij@linaro.org, =?utf-8?q?Martin_Za=C5=A5ovi=C4=8D?= Subject: [PATCHv2 4/4] wiegand: add Wiegand GPIO bit-banged controller driver Date: Thu, 2 Feb 2023 15:33:05 +0100 Message-Id: <20230202143305.21789-5-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230202143305.21789-1-m.zatovic1@gmail.com> References: <20230202143305.21789-1-m.zatovic1@gmail.com> MIME-Version: 1.0 X-Spam-Status: No, score=-1.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1756730988847795442?= X-GMAIL-MSGID: =?utf-8?q?1756730988847795442?= This controller formats the data to a Wiegand format and bit-bangs the message on devicetree defined GPIO lines. Several attributes need to be defined in the devicetree in order for this driver to work, namely the data-hi-gpios, data-lo-gpios, pulse-len, frame-gap and interval-len. These attributes are documented in the devicetree bindings documentation files. The driver creates a dev file for writing messages on the bus. It also creates a sysfs file to control the payload length of messages(in bits). If a message is shorter than the set payload length, it will be discarded. On the other hand, if a message is longer, the additional bits will be stripped off. Signed-off-by: Martin Zaťovič --- .../ABI/testing/sysfs-driver-wiegand-gpio | 9 + MAINTAINERS | 2 + drivers/wiegand/Kconfig | 8 + drivers/wiegand/Makefile | 1 + drivers/wiegand/wiegand-gpio.c | 324 ++++++++++++++++++ 5 files changed, 344 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-driver-wiegand-gpio create mode 100644 drivers/wiegand/wiegand-gpio.c diff --git a/Documentation/ABI/testing/sysfs-driver-wiegand-gpio b/Documentation/ABI/testing/sysfs-driver-wiegand-gpio new file mode 100644 index 000000000000..be2246880a83 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-wiegand-gpio @@ -0,0 +1,9 @@ +What: /sys/devices/platform/.../wiegand-gpio-attributes/payload_len +Date: January 2023 +Contact: Martin Zaťovič +Description: + Read/set the payload length of messages sent by Wiegand GPIO + bit-banging controller in bits. The default value is 26, as + that is the most widely-used length of Wiegand messages. + Controller will only send messages of at least the set length + and it will strip off bits of longer messages. diff --git a/MAINTAINERS b/MAINTAINERS index 54d61d95a1ba..1c6f242aa250 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22438,7 +22438,9 @@ F: include/linux/wiegand.h WIEGAND GPIO BITBANG DRIVER M: Martin Zaťovič S: Maintained +F: Documentation/ABI/testing/sysfs-driver-wiegand-gpio F: Documentation/devicetree/bindings/wiegand/wiegand-gpio.yaml +F: drivers/wiegand/wiegand-gpio.c WILOCITY WIL6210 WIRELESS DRIVER L: linux-wireless@vger.kernel.org diff --git a/drivers/wiegand/Kconfig b/drivers/wiegand/Kconfig index fc99575bc3cc..9a8f705d4646 100644 --- a/drivers/wiegand/Kconfig +++ b/drivers/wiegand/Kconfig @@ -18,3 +18,11 @@ config WIEGAND are initially pulled up. When a bit of value 0 is being transmitted, the D0 line is pulled down. Similarly, when a bit of value 1 is being transmitted, the D1 line is pulled down. + +config WIEGAND_GPIO + tristate "GPIO-based wiegand master (write only)" + depends on WIEGAND + help + This GPIO bitbanging Wiegand controller uses the libgpiod library to + utilize GPIO lines for sending Wiegand data. Userspace may access + the Wiegand GPIO interface via a dev entry. diff --git a/drivers/wiegand/Makefile b/drivers/wiegand/Makefile index d17ecb722c6e..ddf697e21088 100644 --- a/drivers/wiegand/Makefile +++ b/drivers/wiegand/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_WIEGAND) += wiegand.o +obj-$(CONFIG_WIEGAND_GPIO) += wiegand-gpio.o diff --git a/drivers/wiegand/wiegand-gpio.c b/drivers/wiegand/wiegand-gpio.c new file mode 100644 index 000000000000..fc4e7e0e988a --- /dev/null +++ b/drivers/wiegand/wiegand-gpio.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define WIEGAND_MAX_PAYLEN_BYTES 256 + +struct wiegand_gpio { + struct device *dev; + struct wiegand_controller *ctlr; + struct miscdevice misc_dev; + struct mutex mutex; + struct gpio_desc *gpio_data_hi; + struct gpio_desc *gpio_data_lo; + struct file_operations fops; + u8 data[WIEGAND_MAX_PAYLEN_BYTES]; +}; + +struct wiegand_gpio_instance { + struct wiegand_gpio *dev; + unsigned long flags; +}; + +static ssize_t store_ulong(u32 *val, const char *buf, + size_t size, unsigned long max) +{ + int rc; + u32 new; + + rc = kstrtou32(buf, 0, &new); + if (rc) + return rc; + + if (max != 0 && new > max) + return -EINVAL; + + *val = new; + return size; +} + +/* + * Attribute file for setting payload length of Wiegand messages. + */ +ssize_t payload_len_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct wiegand_gpio *wiegand_gpio = (struct wiegand_gpio *) + dev->driver_data; + struct wiegand_controller *ctlr = wiegand_gpio->ctlr; + + return sysfs_emit(buf, "%u\n", ctlr->payload_len); +} + +ssize_t payload_len_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct wiegand_gpio *wiegand_gpio = (struct wiegand_gpio *) + dev->driver_data; + struct wiegand_controller *ctlr = wiegand_gpio->ctlr; + + return store_ulong(&(ctlr->payload_len), buf, count, + WIEGAND_MAX_PAYLEN_BYTES * 8); +} +DEVICE_ATTR_RW(payload_len); + +/* + * To send a bit of value 1 following the wiegand protocol, one must set + * the wiegand_data_hi to low for the duration of pulse. Similarly to send + * a bit of value 0, the wiegand_data_lo is set to low for pulse duration. + * This way the two lines are never low at the same time. + */ +void wiegand_gpio_send_bit(struct wiegand_gpio *wiegand_gpio, bool value, + bool last) +{ + u32 pulse_len = wiegand_gpio->ctlr->pulse_len; + u32 interval_len = wiegand_gpio->ctlr->interval_len; + u32 frame_gap = wiegand_gpio->ctlr->frame_gap; + struct gpio_desc *gpio = value ? wiegand_gpio->gpio_data_hi + : wiegand_gpio->gpio_data_lo; + + gpiod_set_value_cansleep(gpio, 0); + udelay(pulse_len); + gpiod_set_value_cansleep(gpio, 1); + + if (last) + udelay(frame_gap - pulse_len); + else + udelay(interval_len - pulse_len); +} + +/* This function is used for writing from file in dev directory */ +static int wiegand_gpio_write_by_bits(struct wiegand_gpio *wiegand_gpio, + u16 bitlen) +{ + size_t i; + bool bit_value, is_last_bit; + + for (i = 0; i < bitlen; i++) { + bit_value = ((wiegand_gpio->data[i / 8] >> (7 - (i % 8))) + & 0x01); + is_last_bit = (i + 1) == bitlen; + wiegand_gpio_send_bit(wiegand_gpio, bit_value, is_last_bit); + } + + return 0; +} + +static ssize_t wiegand_gpio_get_user_data(struct wiegand_gpio *wiegand_gpio, + char __user const *buf, size_t len) +{ + size_t rc; + + if (len > WIEGAND_MAX_PAYLEN_BYTES) + return -EBADMSG; + + rc = copy_from_user(&wiegand_gpio->data[0], buf, + WIEGAND_MAX_PAYLEN_BYTES); + if (rc < 0) + return rc; + + return len; +} + +static int wiegand_gpio_frelease(struct inode *ino, struct file *filp) +{ + struct wiegand_gpio_instance *info = filp->private_data; + struct wiegand_gpio *wiegand_gpio = info->dev; + + mutex_lock(&wiegand_gpio->mutex); + info->flags = 0; + mutex_unlock(&wiegand_gpio->mutex); + + kfree(info); + + return 0; +} + +static ssize_t wiegand_gpio_fwrite(struct file *filp, char __user const *buf, + size_t len, loff_t *offset) +{ + struct wiegand_gpio_instance *info = filp->private_data; + struct wiegand_gpio *wiegand_gpio = info->dev; + u32 msg_length = wiegand_gpio->ctlr->payload_len; + int rc; + + if (buf == NULL || len == 0 || len * 8 < msg_length) + return -EINVAL; + + rc = wiegand_gpio_get_user_data(wiegand_gpio, buf, len); + if (rc < 0) + return rc; + + wiegand_gpio_write_by_bits(wiegand_gpio, msg_length); + + return len; +} + +static int wiegand_gpio_fopen(struct inode *ino, struct file *filp) +{ + int rc; + struct wiegand_gpio_instance *info; + struct wiegand_gpio *wiegand_gpio = container_of(filp->f_op, + struct wiegand_gpio, + fops); + mutex_lock(&wiegand_gpio->mutex); + if ((filp->f_flags & O_ACCMODE) == O_RDONLY || + (filp->f_flags & O_ACCMODE) == O_RDWR) { + dev_err(wiegand_gpio->dev, "Device is write only\n"); + rc = -EIO; + goto err; + } + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + rc = -ENOMEM; + goto err; + } + + info->dev = wiegand_gpio; + info->flags = filp->f_flags; + mutex_unlock(&wiegand_gpio->mutex); + + filp->private_data = info; + + return 0; +err: + mutex_unlock(&wiegand_gpio->mutex); + return rc; +} + +/* This function is used by device drivers */ +int wiegand_gpio_transfer_message(struct wiegand_device *dev, u8 *message, + u8 msg_bitlen) +{ + struct wiegand_controller *ctlr = dev->controller; + struct wiegand_gpio *wiegand_gpio = wiegand_master_get_devdata(ctlr); + u8 msg_bytelength = (msg_bitlen % 8) ? + (msg_bitlen / 8) + 1 : (msg_bitlen / 8); + + memcpy(wiegand_gpio->data, message, msg_bytelength); + wiegand_gpio_write_by_bits(wiegand_gpio, msg_bitlen); + + return 0; +} + +static int wiegand_gpio_request(struct device *dev, + struct wiegand_gpio *wiegand_gpio) +{ + /* Get GPIO lines using device tree bindings. */ + wiegand_gpio->gpio_data_lo = devm_gpiod_get(dev, "data-lo", + GPIOD_OUT_HIGH); + if (IS_ERR(wiegand_gpio->gpio_data_lo)) + return PTR_ERR(wiegand_gpio->gpio_data_lo); + + wiegand_gpio->gpio_data_hi = devm_gpiod_get(dev, "data-hi", + GPIOD_OUT_HIGH); + return PTR_ERR_OR_ZERO(wiegand_gpio->gpio_data_hi); +} + +static int wiegand_gpio_probe(struct platform_device *device) +{ + int status; + struct wiegand_controller *master; + struct wiegand_gpio *wiegand_gpio; + struct device *dev = &device->dev; + + master = devm_wiegand_alloc_master(dev, sizeof(*wiegand_gpio)); + if (!master) + return -ENOMEM; + + if (dev->of_node) + master->dev.of_node = device->dev.of_node; + + if (status) + return status; + + master->transfer_message = &wiegand_gpio_transfer_message; + master->payload_len = 26; /* set standard 26-bit format */ + + wiegand_gpio = wiegand_master_get_devdata(master); + wiegand_gpio->ctlr = master; + wiegand_gpio->fops.owner = THIS_MODULE; + wiegand_gpio->fops.open = wiegand_gpio_fopen; + wiegand_gpio->fops.release = wiegand_gpio_frelease; + wiegand_gpio->fops.write = wiegand_gpio_fwrite; + + platform_set_drvdata(device, wiegand_gpio); + + master->bus_num = device->id; + wiegand_gpio->dev = dev; + + mutex_init(&wiegand_gpio->mutex); + + status = wiegand_gpio_request(dev, wiegand_gpio); + if (status) { + dev_err(wiegand_gpio->dev, "failed at requesting GPIOs\n"); + return status; + } + + status = gpiod_direction_output(wiegand_gpio->gpio_data_hi, 1); + status |= gpiod_direction_output(wiegand_gpio->gpio_data_lo, 1); + if (status) { + dev_err(wiegand_gpio->dev, "failed to set GPIOs direction\n"); + return status; + } + + status = devm_wiegand_register_master(dev, master); + if (status) { + dev_err(wiegand_gpio->dev, "failed to register master\n"); + return status; + } + + wiegand_gpio->misc_dev.name = kasprintf(GFP_KERNEL, "wiegand-gpio%u", + master->bus_num); + wiegand_gpio->misc_dev.minor = MISC_DYNAMIC_MINOR; + wiegand_gpio->misc_dev.fops = &wiegand_gpio->fops; + + status = misc_register(&wiegand_gpio->misc_dev); + if (status) { + dev_err(wiegand_gpio->dev, "couldn't register misc device\n"); + return status; + } + wiegand_gpio->misc_dev.parent = wiegand_gpio->dev; + + device_create_file(dev, &dev_attr_payload_len); + + return status; +} + +static int wiegand_gpio_remove(struct platform_device *device) +{ + struct wiegand_gpio *wiegand_gpio = platform_get_drvdata(device); + + misc_deregister(&wiegand_gpio->misc_dev); + + return 0; +} + +static const struct of_device_id wiegand_gpio_dt_idtable[] = { + { .compatible = "wiegand-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, wiegand_gpio_dt_idtable); + +static struct platform_driver wiegand_gpio_driver = { + .driver = { + .name = "wiegand-gpio", + .of_match_table = wiegand_gpio_dt_idtable, + }, + .probe = wiegand_gpio_probe, + .remove = wiegand_gpio_remove, +}; + +module_platform_driver(wiegand_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Wiegand write-only driver realized by GPIOs"); +MODULE_AUTHOR("Martin Zaťovič ");