From patchwork Wed Mar 1 14:28:32 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: 62928 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp3661580wrd; Wed, 1 Mar 2023 06:29:17 -0800 (PST) X-Google-Smtp-Source: AK7set8uosETPtOwydeHqIceDmGExSnY+ZTinA3Mk/CLK7Gwag12b+bqKf2AbMatM3uhK+kjc4H6 X-Received: by 2002:a17:902:b7c4:b0:19c:aa17:6660 with SMTP id v4-20020a170902b7c400b0019caa176660mr5881999plz.23.1677680957236; Wed, 01 Mar 2023 06:29:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677680957; cv=none; d=google.com; s=arc-20160816; b=prR/DTaYcfhSTbJBSfaR/JvLK6Wl1r8X+9XnT3x9M8YIAoapsWGPgNjbU8OkWoCGKH N3VXZ5L93+VjpfvWn6kLtWpG2kxdONC8aT+awY9EVjTqjApkyJG5r3nbvKfQa48MO3XT 0GsbcT2UGk2uXOP7mOJJUAganbWNCnbOLHpbyy+fOc1XTsY91wHoUhhAtJBD0m6yDaNa d860uc9l/NEzqaRHnMJDhDHEBvk+EFzJ//2MAHcyUMoQaGjFDbkZaYyDHHzYKMF5QLfA P1aTHopThKIwseqE0y423+wurh8k/Olu3+/kzZw3lmLI8H0rl9MmMVqAZLvyD6xWa5hD /WlQ== 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=Qraxm/9HXdh2HNOxnclG1G7KZkQPcMY4/tQTySpYdVE=; b=sswVGO0zdKp4nFcSGu0OEAdATOdbs2FC5CTHMM+cYK6x+fMaO5lhWJWY0naH9wa3Nr 0FQskTOiGPRTtdE7yOF09uP1IOhcxF0035FGgi/6QhDim3IUs3/rYEmYrOjVxZR8boyO sIzqdeWnyuChO9E46axF+WBbWssN5S79xq8zBikX5MNjMog95JfH0V/6uqykmrFWrNfV KBrbROQ2dNCWRKhFu7y+zsnNev+/iye+dfYEAqzUJay+m7O7viuRonS4YREQHm5e/2+6 BLiD519xmuPCnPTaCrRga8SSH32qsmHFB01Fef8GjxIRDrOYapWMtMGwYBgDSHC/AhqP Z0tA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=D3i5prvB; 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 kf15-20020a17090305cf00b0019cb644b891si12078827plb.512.2023.03.01.06.29.02; Wed, 01 Mar 2023 06:29:17 -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=D3i5prvB; 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 S230173AbjCAO24 (ORCPT + 99 others); Wed, 1 Mar 2023 09:28:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53446 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229806AbjCAO2x (ORCPT ); Wed, 1 Mar 2023 09:28:53 -0500 Received: from mail-ed1-x533.google.com (mail-ed1-x533.google.com [IPv6:2a00:1450:4864:20::533]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EA289199C5; Wed, 1 Mar 2023 06:28:51 -0800 (PST) Received: by mail-ed1-x533.google.com with SMTP id i34so54489760eda.7; Wed, 01 Mar 2023 06:28:51 -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=Qraxm/9HXdh2HNOxnclG1G7KZkQPcMY4/tQTySpYdVE=; b=D3i5prvBSoDAcYNiuUu7+Ssu1m/BFGlOVvRWt7XGwrnAZMMjAKCR6v4T/PI3GB76Qs Obgw7A4jpZ7PipFKe7tAATehnUfTGpylcNMFettfQpwC13grefuOYknBfcjxCnG3HAeh KpSesNJxfIhJhMR+JdvQIfpGA73k3WMIP7a2yw7pgQWxxD79hk9vsGCggOL2cWaSWelE LFEBwCSJAXogAJe8o1Jj8/mf2tv0J9KKXchTQ4Z/7US4mrIvauapmIPknTjZYJNUMBp2 /DLrjfk+FsuD9teHeFW+Y4bP2hf8IG+0gStMWxCl/cIbO7yjcxj3WtsvaYpmb6jVr1Ud hNVw== 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=Qraxm/9HXdh2HNOxnclG1G7KZkQPcMY4/tQTySpYdVE=; b=SaOVOUxLOQzyrAm/Mid7xuNIssdbnc73fdwW0ioZPTr0EAKnbyIBrG0Qjd8LHGoz9U eOEbLXmhPIamRgk7mpu9DOz/tgpFcNlBCiseDI4DUApurvRZk2UE5Ik4kH1mdCcnIRGj VKeif3Ew/SENsJ5n8Zzn8BeKHEIEjzQaW+mKkTuFzmT79VCZ0VpKsGAJ/LBLpWGkjssh 8kBfcEQ4t/gdX854x7scQLz6o2u+K/nvYReWmb01+D0quk3pdeqxmQ8GQsKWOtD/oczy 4TB8uu3SF5bkpenXEQpSNySf4UtY4zF87tc4SVLjLulg/8uejLjlZpoZnhHCCGHCXP47 JWWQ== X-Gm-Message-State: AO0yUKV2HvDoGRYdfzyF3DCz9M80R/NB3ImHIagVj37WkcvoQZqYSfrf URcb8TfDUQKToJWP9/WjvxSSppfYugvR+w== X-Received: by 2002:a05:6402:416:b0:4ad:7c30:2599 with SMTP id q22-20020a056402041600b004ad7c302599mr8180696edv.13.1677680930210; Wed, 01 Mar 2023 06:28:50 -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 t8-20020a170906178800b008dcf89a72d7sm5972282eje.147.2023.03.01.06.28.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Mar 2023 06:28:49 -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, airlied@redhat.com, dipenp@nvidia.com, treding@nvidia.com, mwen@igalia.com, fmdefrancesco@gmail.com, arnd@arndb.de, bvanassche@acm.org, ogabbay@kernel.org, axboe@kernel.dk, mathieu.poirier@linaro.org, linux@zary.sk, masahiroy@kernel.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, jacek.lawrynowicz@linux.intel.com, benjamin.tissoires@redhat.com, devicetree@vger.kernel.org, furong.zhou@linux.intel.com, andriy.shevchenko@intel.com, linus.walleij@linaro.org, =?utf-8?q?Martin_Za?= =?utf-8?q?=C5=A5ovi=C4=8D?= Subject: [PATCHv3 1/4] dt-bindings: wiegand: add Wiegand controller common properties Date: Wed, 1 Mar 2023 15:28:32 +0100 Message-Id: <20230301142835.19614-2-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230301142835.19614-1-m.zatovic1@gmail.com> References: <20230301142835.19614-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?1759175987443506136?= X-GMAIL-MSGID: =?utf-8?q?1759175987443506136?= Wiegand 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. Acked-by: Linus Walleij Signed-off-by: Martin Zaťovič Reviewed-by: Rob Herring --- .../bindings/wiegand/wiegand-controller.yaml | 39 +++++++++++++++++++ MAINTAINERS | 5 +++ 2 files changed, 44 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..df985cb3045a --- /dev/null +++ b/Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml @@ -0,0 +1,39 @@ +# 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 diff --git a/MAINTAINERS b/MAINTAINERS index b0db911207ba..1f6f6d236f0c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22512,6 +22512,11 @@ L: linux-rtc@vger.kernel.org S: Maintained F: drivers/rtc/rtc-sd3078.c +WIEGAND BUS DRIVER +M: Martin Zaťovič +S: Maintained +F: Documentation/devicetree/bindings/wiegand/wiegand-controller.yaml + WIIMOTE HID DRIVER M: David Rheinsberg L: linux-input@vger.kernel.org From patchwork Wed Mar 1 14:28:33 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: 62929 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp3661640wrd; Wed, 1 Mar 2023 06:29:26 -0800 (PST) X-Google-Smtp-Source: AK7set8c9Ng2wt2OkXC1Z67aR4UspDuiX/PNegQUYQmluJAv/Cb0JTSMjjBDiFCXBd/sl0B03qj2 X-Received: by 2002:a05:6a20:4420:b0:b9:2df:7ef6 with SMTP id ce32-20020a056a20442000b000b902df7ef6mr8632685pzb.31.1677680966471; Wed, 01 Mar 2023 06:29:26 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677680966; cv=none; d=google.com; s=arc-20160816; b=bsyCqR5HFIFfNl6YAShiGipqzgcsBNYR+yIEBJTh8WvFy5OYGIn5z3DMVJlNKVUa8O 6AZxL20M5NjTbKopEx7Fo0reQ6ecSj4kbJD4uY1LUvJ3+44O/j92DVxrDkDlsvYvWnxU DKB2Aj8xzyrrenN89TJrdAcbcFKWWtZy7WHBS7LVra4XuQ3IEwssoQfsfC6UEPWco4ej cON57G0YMKafixTQwNLVKRH+YCvCF333t1dlXRJki7ns3lerkDRsJ07ZiyifEE1MVSzr R7zxNMF28NBS5mRHc3f+Tr1rKLUHEIJOzySy8iRjlDQ/llzr4e2CA07ZoU+XEh5ZQ2bg Ljmw== 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=U0yVA58GaC3n6H36VuEv9LWqoXqWPCxUn0npZ2+wTRI=; b=XQISYBxGciFInf4l8iE3mTMo/l2OyaEXzBLzNdFR4NL9RI+qEqUvHVBFbeg/V/kkRj +R/Jp31KB+wpWi6DjwHcCCEsGhdow9mwwt1/trG7lF8rvmrrwi6PZXVapU0HrKmVeQso L8lTKCJ95WyDueNuamk3XtfyKWuQ4yHGiINrx/vbKGCUsoCD2rmkB+bDcTU8ZXZsv90S kEu9PKdtkNCwx2XpGrPGCXMnVQDY6bwpiB/7v0PAk+J4CbIHr6tMSutXLL9JpXHzGTMQ lWbvXNiW1uw+hcVziVqjimcLSGPdIHHRX0DKe8YLbCV0FGgYk2eH4f1GWOeQvLARIViZ +dWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=pY40YaTk; 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 t19-20020a639553000000b004ce5301ee14si12118659pgn.763.2023.03.01.06.29.13; Wed, 01 Mar 2023 06:29:26 -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=pY40YaTk; 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 S230205AbjCAO26 (ORCPT + 99 others); Wed, 1 Mar 2023 09:28:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53442 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230170AbjCAO24 (ORCPT ); Wed, 1 Mar 2023 09:28:56 -0500 Received: from mail-ed1-x530.google.com (mail-ed1-x530.google.com [IPv6:2a00:1450:4864:20::530]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3C16D4696; Wed, 1 Mar 2023 06:28:54 -0800 (PST) Received: by mail-ed1-x530.google.com with SMTP id da10so54616924edb.3; Wed, 01 Mar 2023 06:28:54 -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=U0yVA58GaC3n6H36VuEv9LWqoXqWPCxUn0npZ2+wTRI=; b=pY40YaTk+Xcb+lMTso2R8DYrEwMbMLZqIM4d9UjwlFdAxOFRRRV0BmmxXKORPm+a87 Hn8CyiD57ZqUMyHc0DSdGC9uW1qRtA6US7NvuOhjKf0XErNh1C9MZX5z92cFvtmzhHRT L9IOHb6pzo4i21mhZZHmj+WtLA+Tn3rcR6zOYjxJqmlH9sZsY28oRDHXq8HMb7b011R8 +puSw7V3jZRESK/f6N3vyj2bShNOvDAsljIv9QXfFYqEHCpNrMPbjxBUQEU/ICEzOhqx 7iE9ynY0BLt+XTZUbhshXakz/Zb12TMHXn35Ws/tyvYdKrxTgRFd2Czeubl/oiZTAwRi OpMA== 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=U0yVA58GaC3n6H36VuEv9LWqoXqWPCxUn0npZ2+wTRI=; b=sbM/5q7XpS8iqp0y1oI/+oEYZq9JsoGCahtrhy708ADw3ywOguEdALlc+A0bPG8njs hyvQGTfxT2piudTjd3pOzUkDZ0dmJe+85OFifz34k41q6oPTj0Djv/s73oWuTBpBdGjw TuIRufL/vtoNoNXqiUB+b+mHewvreLgA2iVd4eNTodx3CjwvBvGzXH8TX3jqrxnFg0lX be/ulttXSyAZpF7FYtNjd/zTJU07d5X5YZpOxS2Gkhb4YoQep5Wz3FcLODHTQpK0P0Ng yEg1kh4ZwtoOL3AtCXWlLQ/ymErb+MK+Z/tFA21Ike1OBz0nUkyAtR1IuIRrkSkqd/gK aUXA== X-Gm-Message-State: AO0yUKVYC/GVad4xel3c9K6kX5/JidrsFqAUC9DWrhN3I2/7gC3COuPL sjDuKwuN4mSMiJhNo7yqlK26C6jd7IgMDA== X-Received: by 2002:a05:6402:1b06:b0:4af:7f6e:297b with SMTP id by6-20020a0564021b0600b004af7f6e297bmr7767856edb.35.1677680932565; Wed, 01 Mar 2023 06:28:52 -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 t8-20020a170906178800b008dcf89a72d7sm5972282eje.147.2023.03.01.06.28.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Mar 2023 06:28:52 -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, airlied@redhat.com, dipenp@nvidia.com, treding@nvidia.com, mwen@igalia.com, fmdefrancesco@gmail.com, arnd@arndb.de, bvanassche@acm.org, ogabbay@kernel.org, axboe@kernel.dk, mathieu.poirier@linaro.org, linux@zary.sk, masahiroy@kernel.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, jacek.lawrynowicz@linux.intel.com, benjamin.tissoires@redhat.com, devicetree@vger.kernel.org, furong.zhou@linux.intel.com, andriy.shevchenko@intel.com, linus.walleij@linaro.org, =?utf-8?q?Martin_Za?= =?utf-8?q?=C5=A5ovi=C4=8D?= Subject: [PATCHv3 2/4] wiegand: add Wiegand bus driver Date: Wed, 1 Mar 2023 15:28:33 +0100 Message-Id: <20230301142835.19614-3-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230301142835.19614-1-m.zatovic1@gmail.com> References: <20230301142835.19614-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?1759175997160006915?= X-GMAIL-MSGID: =?utf-8?q?1759175997160006915?= 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. Acked-by: Linus Walleij 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 | 500 ++++++++++++++++++++++++++++++++++++++ include/linux/wiegand.h | 155 ++++++++++++ 7 files changed, 681 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 1f6f6d236f0c..23a67b32f095 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22516,6 +22516,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 WIIMOTE HID DRIVER M: David Rheinsberg 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 20b118dca999..ef96e937eacc 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -150,6 +150,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..d6b63250e80b --- /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..ebec2e3e4cd6 --- /dev/null +++ b/drivers/wiegand/wiegand.c @@ -0,0 +1,500 @@ +// 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 DEFINE_MUTEX(board_lock); + +static void devm_wiegand_release_controller(struct device *dev, void *ctlr) +{ + wiegand_controller_put(*(struct wiegand_controller **)ctlr); +} + +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.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); + +/** + * wiegand_controller_check_ops - checks whether message transfer function was defined for a + * controller + * @ctlr: controller structure to check + */ +static int wiegand_controller_check_ops(struct wiegand_controller *ctlr) +{ + if (!ctlr->transfer_message) + return -EINVAL; + return 0; +} + +/** + * of_register_wiegand_device - allocates and registers a new Wiegand device based on devicetree + * node + * @ctlr: controller structure to attach device to + * @nc: devicetree node for the device + */ +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; + } + + 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); +} + +/** + * of_register_wiegand_devices - creates a wiegand device for all children of a controller + * devicetree node + * @ctlr: controller structure to check + */ +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); + } + } +} + +/** + * wiegand_register_controller - registers controller structure within bus + * @ctlr: controller structure to register + * + * Function checks that the message transfer functions is defined for passed controller structure, + * gets the devicetree defined attributes and checks whether they have all been initialized and + * finally adds the controller device and registers the controller on the bus. + */ +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, setting the default value 50us\n"); + ctlr->pulse_len = 50; + } + if (ctlr->interval_len == 0) { + dev_warn(&ctlr->dev, "interval_len is not initialized, setting the default value 2000us\n"); + ctlr->interval_len = 2000; + } + if (ctlr->frame_gap == 0) { + dev_warn(&ctlr->dev, "frame_gap is not initialized, setting the default value 2000us\n"); + ctlr->frame_gap = 2000; + } + + 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); + +/* 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) +{ + if (of_driver_match_device(dev, drv)) + return 1; + + return 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 int wiegand_remove(struct device *dev) +{ + const struct wiegand_driver *wdrv = to_wiegand_driver(dev->driver); + + if (wdrv->remove) + wdrv->remove(to_wiegand_device(dev)); + + return 0; +} + +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 (wdrv->driver.name) { + 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); + return ret; + } + + return 0; +} + +static void __exit wiegand_exit(void) +{ + bus_unregister(&wiegand_bus_type); +} +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..9dc683d91b3d --- /dev/null +++ b/include/linux/wiegand.h @@ -0,0 +1,155 @@ +/* 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; + + s16 bus_num; + + bool slave; + bool devm_allocated; + + u32 pulse_len; + u32 interval_len; + u32 frame_gap; + u32 payload_len; + u8 device_count; + + 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 +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); +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 */ + +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); +} + +static inline struct wiegand_driver *to_wiegand_driver(struct device_driver *drv) +{ + return drv ? container_of(drv, struct wiegand_driver, driver) : NULL; +} + +#endif /* H_LINUX_INCLUDE_LINUX_WIEGAND_H */ From patchwork Wed Mar 1 14:28:34 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: 62930 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp3661725wrd; Wed, 1 Mar 2023 06:29:39 -0800 (PST) X-Google-Smtp-Source: AK7set++p8j1nHTm6lAfZ3syiTRmS2rZXDZwbJb1W+2HvNbD25p1JorDLvxR0OZmAtef6wYoC/5p X-Received: by 2002:a05:6a21:7881:b0:bf:8a97:6e48 with SMTP id bf1-20020a056a21788100b000bf8a976e48mr8236455pzc.37.1677680978904; Wed, 01 Mar 2023 06:29:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677680978; cv=none; d=google.com; s=arc-20160816; b=J48AYwF4hyYlu7mV47WMwmOgYkHjqeMTj9EDzw8Tw7LzD4p202jQijpjn/7KDzLf19 kfDg1nTsk9333yhk8+C4D47S9JPreanNbdCNrxvQ3l2acfJfiOKhRYD3dintvocOloTy HO78LNn+UAQJBuXz03ahNOlH+yaddL2/VEYWDfL2q6zOI95CKfKbZRvmJZZX2KuXaSj4 0kd7YIwFWQ8zr0t/EWB5ZM/aZ79FL+LdeNdtgaGBwsHPFykYQFoKs5KKGTGQ5/AEsu3U 6MU9LcoFdYoWZESkbJYn7/ElPI05jfxs5jAcg3z8/1M4FZrmPLSuc7Uk41c7yW2/HHxu CttA== 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=LIK1zlcDtzGzZUoPfFsY1qnnB3Dv1hWrxQ0eoBZLglg=; b=NGRrKc83oRBxWxlroKqnrpSi6vtAO/iLBLEd3/NPYejIWRRe7wwAWGkJmtzV947iV0 y2rZNmiqZwJM/16sy7UoFz1O4FAY8PXfLQdOtZLlnz9XK2hyIAFWXfEK4erjjouH0zOL k4vX6TiI44Ada1EvrghDr0SY8ko/qBg7MGQppqzNVgo7mZ/2nGYA+BnJsGsn8ktO/Mmi 74V0kiRn3258qUhJjM8KXfbyRSN8/u2Vck4OmUK0U1EOg2SFYJK381b68NAWFYXoM7nq 7pEXmyZUYMBeSMt4nIOXGGflGF9mDBuDLTU77cyIv0iNpLtmxeyZNhr6X/XYTn+c5YsW Gl3Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=Mlmlpzzs; 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 r132-20020a632b8a000000b0050327dc6000si11360274pgr.822.2023.03.01.06.29.25; Wed, 01 Mar 2023 06:29:38 -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=Mlmlpzzs; 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 S230213AbjCAO3C (ORCPT + 99 others); Wed, 1 Mar 2023 09:29:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53558 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229806AbjCAO25 (ORCPT ); Wed, 1 Mar 2023 09:28:57 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4C1E21B33E; Wed, 1 Mar 2023 06:28:56 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id cq23so54647277edb.1; Wed, 01 Mar 2023 06:28:56 -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=LIK1zlcDtzGzZUoPfFsY1qnnB3Dv1hWrxQ0eoBZLglg=; b=MlmlpzzsYNljnIJffqf1a7CYsFtxeYOiLIphYeOpbxlbZdzzaEBgGcqiuqV7xjX0sb Yxq5Gn6LiUFD5pw5Je+lMZgNrfIJZhdLrkuPwDSR2wZaJ4DS2L+CBJP/QU15pMb/Eve8 H0+iuAzm8LNjJZ6YpxA/UutoOrRN/4KnTqh+4XBBEBabB8E4sW+LIKh7e/AapaMKh2Be PlTECaDUk00J5e37Z8k3ZesourLmdpxCaYKulZ2xAGUC5en8sHYpc3ypnEfVV+JK3zGM oJnZIhWVmueGQoPqFyBq+dMz/6jTukEXb8OaYrl7O97KhhxIRfjr2mX14RyRaZ30QGAF 4nMQ== 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=LIK1zlcDtzGzZUoPfFsY1qnnB3Dv1hWrxQ0eoBZLglg=; b=N/i6T7Rx57bpLLYCsP1ubf8wBImLhSrzbL94I2wWz0Tqjy9eFQo0Y+kUO2yPwczQCF hea4oQG0kzQAcIrHAuxKUjAQ0JAOvcqE07kZKfx11bGOsvvUJrRgwkQQi+BbOyX4SXPB aorXkPdVSR5etbSj9F4UL16gzm9RJaESyUoMi+m0cU0Zgaaw6fBhVDjNdSf10FBzb7uo mDEMVJwhEiBwgxuFxC+tcwAgpMm7cQ3Cuyzk1eLn4UgEpMl+did6ZekgTox0u5M/SOup PamszRe2dfHnhrucEoASLeVvaED1EFA5agitWCDRYhkkXrgS1w3h4IFFw2yjO7zGIEtK aS8Q== X-Gm-Message-State: AO0yUKXfADGsKaJPGulhzz848/Gd0R0POpiFlw+PLBuV8j38qXt7RXTB C9vZ+OnBfkM9j/cfojnVMfhBu0SBXe8jJQ== X-Received: by 2002:aa7:c7cc:0:b0:4ac:bbc7:aa8e with SMTP id o12-20020aa7c7cc000000b004acbbc7aa8emr6134099eds.41.1677680934606; Wed, 01 Mar 2023 06:28:54 -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 t8-20020a170906178800b008dcf89a72d7sm5972282eje.147.2023.03.01.06.28.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Mar 2023 06:28:54 -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, airlied@redhat.com, dipenp@nvidia.com, treding@nvidia.com, mwen@igalia.com, fmdefrancesco@gmail.com, arnd@arndb.de, bvanassche@acm.org, ogabbay@kernel.org, axboe@kernel.dk, mathieu.poirier@linaro.org, linux@zary.sk, masahiroy@kernel.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, jacek.lawrynowicz@linux.intel.com, benjamin.tissoires@redhat.com, devicetree@vger.kernel.org, furong.zhou@linux.intel.com, andriy.shevchenko@intel.com, linus.walleij@linaro.org, =?utf-8?q?Martin_Za?= =?utf-8?q?=C5=A5ovi=C4=8D?= Subject: [PATCHv3 3/4] dt-bindings: wiegand: add GPIO bitbanged Wiegand controller Date: Wed, 1 Mar 2023 15:28:34 +0100 Message-Id: <20230301142835.19614-4-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230301142835.19614-1-m.zatovic1@gmail.com> References: <20230301142835.19614-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?1759176009652499144?= X-GMAIL-MSGID: =?utf-8?q?1759176009652499144?= 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). Acked-by: Linus Walleij 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..df28929f6dae --- /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 23a67b32f095..91e573466d6b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22519,6 +22519,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 + WIIMOTE HID DRIVER M: David Rheinsberg L: linux-input@vger.kernel.org From patchwork Wed Mar 1 14:28:35 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: 62931 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:5915:0:0:0:0:0 with SMTP id v21csp3667478wrd; Wed, 1 Mar 2023 06:40:24 -0800 (PST) X-Google-Smtp-Source: AK7set9PgqVn4p5XVlO9/1S0dDK86rdaUu5/vmuYX51VI7seVWtSX9j1y4JBh2RPrY0ncGW0+9qh X-Received: by 2002:a17:903:284f:b0:19d:90f:6c39 with SMTP id kq15-20020a170903284f00b0019d090f6c39mr5405707plb.50.1677681624342; Wed, 01 Mar 2023 06:40:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677681624; cv=none; d=google.com; s=arc-20160816; b=xqLX7iJYxvCQ0T89O6TFgP0tKtVNj9SHmj6jY9f0iSOQrwtsQR0H2asFu9W35PXiya E9pjj0sQFGJrN8DOFfX5TyUVWXb967oLe+k71THtdFPI+uW+EG/uxXys/ljjjsnoUej0 eXf11CIghAylXiQFirAEnuD0j3DndAI5TbpUeHSEZm0w2aNWgdcrq6LNggMcHZCGFMc8 M4Q1mb2E4VZd/sEI2TgyVq+EBwL3DM+ZMjjLnRZDSuCPx44tfBOFYpN0622m2rvO85Dm Uq/wAxnZB5a9eNv9iTYO4wI5mqlbUMMIMHXbEo9EPgmSWNgj8murIjkFtTC31CDhrxBs nnRQ== 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=iclZ11jzipPQaEkBiD57/nQz5zRbGvKcq2FeaTkbORY=; b=oDifiWf4giFMmnhrTu+eVowVbrIP4m0rq1YMOaPI49Zcxj/0g22w/mTFXybhCz8mM0 zaEESD9yoBfukCG3OwX514K5MsfImXl/66EX8PvZmhq8LxfefwanX9U4K8SD1Df6q6Qf 6SqFJnZFk04Pdhv1cZiYQPohpjgzpvTaFcKTpck8NqaTeRBZUh+sbjWFMdYgD+W+mov1 dAQroDvOzfuD52jybepVpqxzqD0fyfd7TG+DutLf/UltlApq6opfTZCsV/scChtqANHe 7U1Fb+mMO9/nugRAIny4GR87nkMbKm7ICSWa7Aj1yth9LVSHKT/Gwhob/Pic+XFti91p g34g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b=hcJL0QuL; 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 6-20020a170902ee4600b0019ca7ed8931si12267875plo.279.2023.03.01.06.40.02; Wed, 01 Mar 2023 06:40:24 -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=hcJL0QuL; 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 S230254AbjCAO3M (ORCPT + 99 others); Wed, 1 Mar 2023 09:29:12 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53442 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230227AbjCAO3J (ORCPT ); Wed, 1 Mar 2023 09:29:09 -0500 Received: from mail-ed1-x535.google.com (mail-ed1-x535.google.com [IPv6:2a00:1450:4864:20::535]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AB3131E05; Wed, 1 Mar 2023 06:28:58 -0800 (PST) Received: by mail-ed1-x535.google.com with SMTP id cq23so54647812edb.1; Wed, 01 Mar 2023 06:28:57 -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=iclZ11jzipPQaEkBiD57/nQz5zRbGvKcq2FeaTkbORY=; b=hcJL0QuLGnZvgbZUg2pFOTY53ESxCcsMUM4jqH2xVo5e4xsS0GiEqF14yDcVJ9m3+3 CFXONbFVzu4KYljfzI5KTuBipYqGWv862l8I7slP8U/wROqXODWVahTG2r3boJTnGYDO FjcR90jTO85s91cVBRfd9Pr2AAQH5ZrRNkVKsZtjJYn2BTlmllDdwqSJ1G5ixfCPdQfb n5vYvzzjl4jR7fNMCrVLVX4J8lUU0mN1NknG4Oke3hLm6irPikNwfPQ6u4tXqcqlSyl1 GKqd4IRXCzvpm2SKwWUU/7PNSNAzUPPU7TAYDwHvl82U5qw8C4sq7F176I0uSmaJ8T7a F9xw== 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=iclZ11jzipPQaEkBiD57/nQz5zRbGvKcq2FeaTkbORY=; b=HG9BGt8pEE0Scx/Vo/SLv/kNDDvVt+u/QBgyCUbocLPFGBWSBJsgoCbrT6BmxErbgU rOYCV3sOmsYrZOkqwsLNMWV1lBF6D3h4gfM2Ba8z+2KCPWPRmT8hiFyDspYI3H0zJA3I Ih7ktWQUvdgVu7N9P5G3zxvNgPTaO9/00L2KQ9/o9Vz+bCkshPWMmEsX7g0BoPTqMoRI elTRarb8spgWy8mCzBZbbR2uQFlAnAPNfzJRxY5yPV5Z5fAp4Ql4OFv+TxQkzpO9jUwh 7Xy9W8l2iqx1jVF+yKFqUvIy2tgk8E2FNtIWMSWvsvWE0Ie4PIg7KRFH56sWt4N0yMy4 wGJA== X-Gm-Message-State: AO0yUKVZsK9vwlFqGKKRh9v7iUzwF1rrnWXBBMo2gZbeHjPwuPqpaWJR 8VLezTZJB7ilpm66MMTONARtdnhDKMYEsg== X-Received: by 2002:a17:907:25c2:b0:887:dea8:b029 with SMTP id ae2-20020a17090725c200b00887dea8b029mr7046524ejc.1.1677680937429; Wed, 01 Mar 2023 06:28:57 -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 t8-20020a170906178800b008dcf89a72d7sm5972282eje.147.2023.03.01.06.28.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 01 Mar 2023 06:28:56 -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, airlied@redhat.com, dipenp@nvidia.com, treding@nvidia.com, mwen@igalia.com, fmdefrancesco@gmail.com, arnd@arndb.de, bvanassche@acm.org, ogabbay@kernel.org, axboe@kernel.dk, mathieu.poirier@linaro.org, linux@zary.sk, masahiroy@kernel.org, yangyicong@hisilicon.com, dan.j.williams@intel.com, jacek.lawrynowicz@linux.intel.com, benjamin.tissoires@redhat.com, devicetree@vger.kernel.org, furong.zhou@linux.intel.com, andriy.shevchenko@intel.com, linus.walleij@linaro.org, =?utf-8?q?Martin_Za?= =?utf-8?q?=C5=A5ovi=C4=8D?= Subject: [PATCHv3 4/4] wiegand: add Wiegand GPIO bitbanged controller driver Date: Wed, 1 Mar 2023 15:28:35 +0100 Message-Id: <20230301142835.19614-5-m.zatovic1@gmail.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230301142835.19614-1-m.zatovic1@gmail.com> References: <20230301142835.19614-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?1759176686887229442?= X-GMAIL-MSGID: =?utf-8?q?1759176686887229442?= 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. Acked-by: Linus Walleij 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 | 316 ++++++++++++++++++ 5 files changed, 336 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 91e573466d6b..eeeb343ee91c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22522,7 +22522,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 WIIMOTE HID DRIVER M: David Rheinsberg diff --git a/drivers/wiegand/Kconfig b/drivers/wiegand/Kconfig index d6b63250e80b..d3a6c773c767 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..e67a30a1c5ae --- /dev/null +++ b/drivers/wiegand/wiegand-gpio.c @@ -0,0 +1,316 @@ +// 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 = dev_get_drvdata(dev); + 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 = dev_get_drvdata(dev); + 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); + +static struct attribute *wiegand_gpio_attrs[] = { + &dev_attr_payload_len.attr, + NULL, +}; + +ATTRIBUTE_GROUPS(wiegand_gpio); + +/* + * 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); + dev->groups = wiegand_gpio_groups; + + 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č ");