From nobody Mon Apr 13 12:01:09 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2D957C25B0D for ; Wed, 10 Aug 2022 14:07:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232969AbiHJOHz (ORCPT ); Wed, 10 Aug 2022 10:07:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45512 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232556AbiHJOHs (ORCPT ); Wed, 10 Aug 2022 10:07:48 -0400 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17D3D6E2F9 for ; Wed, 10 Aug 2022 07:07:44 -0700 (PDT) Received: by mail-wr1-x434.google.com with SMTP id l22so17894387wrz.7 for ; Wed, 10 Aug 2022 07:07:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=pqhA8o+boQJA8OSHBFOoAbjBpl0hxdmasRE4keRadHE=; b=cTw+eVTyPlg5bzYxedeopN4BqOZpMeSPQWJvU78DKS+jhKJfslT4pMC4XUU/O/863n C+0yxkWzB//75y41NTcZgZEeEWdEBzAdZy2LMxgsMbjMvp16r2bdA4ZCFN5VLiZqrjcK yC5aa31sJdh6olAqmnuDtKQ2sdIs76SYH7JgAKKqxBR3HoMr9sPctN9pGYh5l0dVsvQE o956Rx7AMAQdzqszqEa/pIcfc/tC4Fn/0pSa9HLdSRVKzaxIcbod2juyE0+LWV212LP1 qHxgjZeERN5vk3Vd3E+pYtfHK7ywlq4/dWf4/9A9/LSX0DywNzo6wVCFSHj5ifIE4OYg ZeNQ== 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; bh=pqhA8o+boQJA8OSHBFOoAbjBpl0hxdmasRE4keRadHE=; b=DPdIEpbwTJ1TnyDJ76dsa3tX52emY+TAw+oynS6Gw5KxPrFtTIhtHzBCnFlmcEpIa8 e6pzJ0Qp5GhGejJsysj2oenvXScneBADcc8r3eJAJUKqu03wpmbCNcBB8nu3fCAdtJSi 2txufivu37q2eD2wBdK3o0K0YqXt/Sofgvf/sNNIHy1IMGXmW8/wDx9lGabbS7T180jm m2ufjQPS9M8fIo8+FKW1pgXjsWYVeBjgCw84rk7HxI9JXH/S2ovdDGS55skBr2Nkr2Nu +GwfnEfzmY/fmOlI09TT/1XaiJAu0pX/zfABxU4yz1NI9XVCd1LzgXeBbUQ6mi5rwudB Dxeg== X-Gm-Message-State: ACgBeo13Q99RvA42zxcMUy5sv4epf6hARAmfSMSoCjBCtnP8PXPI6ouW b3Eq0tZil1qX4td/LVnD44yLwg== X-Google-Smtp-Source: AA6agR7Au3nWd8WrJiE+4lhi3rDCe2+VabP8fkIHAszisl0dnDTnBDb7/9Wu5f4TS1TR4ua3rpOzGg== X-Received: by 2002:adf:fdcb:0:b0:21f:ae9:bbd1 with SMTP id i11-20020adffdcb000000b0021f0ae9bbd1mr16199087wrs.506.1660140462630; Wed, 10 Aug 2022 07:07:42 -0700 (PDT) Received: from localhost.localdomain (32.31.102.84.rev.sfr.net. [84.102.31.32]) by smtp.gmail.com with ESMTPSA id o15-20020adfcf0f000000b0021d6a520ce9sm16258229wrj.47.2022.08.10.07.07.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Aug 2022 07:07:41 -0700 (PDT) From: Julien Panis To: vilhelm.gray@gmail.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, mranostay@ti.com, Julien Panis , Krzysztof Kozlowski Subject: [PATCH v4 1/3] dt-binding: counter: add ti,am62-ecap-capture.yaml Date: Wed, 10 Aug 2022 16:07:22 +0200 Message-Id: <20220810140724.182389-2-jpanis@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220810140724.182389-1-jpanis@baylibre.com> References: <20220810140724.182389-1-jpanis@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This commit adds a YAML binding for TI ECAP used in capture operating mode. Signed-off-by: Julien Panis Reviewed-by: Krzysztof Kozlowski --- .../counter/ti,am62-ecap-capture.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/counter/ti,am62-ecap-= capture.yaml diff --git a/Documentation/devicetree/bindings/counter/ti,am62-ecap-capture= .yaml b/Documentation/devicetree/bindings/counter/ti,am62-ecap-capture.yaml new file mode 100644 index 000000000000..4e0b2d2b303e --- /dev/null +++ b/Documentation/devicetree/bindings/counter/ti,am62-ecap-capture.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/counter/ti,am62-ecap-capture.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Texas Instruments Enhanced Capture (eCAP) Module + +maintainers: + - Julien Panis + +description: | + The eCAP module resources can be used to capture timestamps + on input signal events (falling/rising edges). + +properties: + compatible: + const: ti,am62-ecap-capture + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: fck + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + + soc { + #address-cells =3D <2>; + #size-cells =3D <2>; + + capture@23100000 { /* eCAP in capture mode on am62x */ + compatible =3D "ti,am62-ecap-capture"; + reg =3D <0x00 0x23100000 0x00 0x100>; + interrupts =3D ; + power-domains =3D <&k3_pds 51 TI_SCI_PD_EXCLUSIVE>; + clocks =3D <&k3_clks 51 0>; + clock-names =3D "fck"; + }; + }; --=20 2.25.1 From nobody Mon Apr 13 12:01:09 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C7F57C00140 for ; Wed, 10 Aug 2022 14:07:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232970AbiHJOHv (ORCPT ); Wed, 10 Aug 2022 10:07:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45430 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232963AbiHJOHq (ORCPT ); Wed, 10 Aug 2022 10:07:46 -0400 Received: from mail-wm1-x32c.google.com (mail-wm1-x32c.google.com [IPv6:2a00:1450:4864:20::32c]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B1AAB6E883 for ; Wed, 10 Aug 2022 07:07:45 -0700 (PDT) Received: by mail-wm1-x32c.google.com with SMTP id h204-20020a1c21d5000000b003a5b467c3abso512466wmh.5 for ; Wed, 10 Aug 2022 07:07:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=saNlXTXB51vCTSXiZxahbXz4v7+9GH/MAa0h7DJY6Cs=; b=Rp2dXb668XuG/+hI6ohbx1Dq80GfHGdQ/2Cl16uoMtyaW9JsI+yU4meP34bODv3m/T FKOBsLPVIm8GX3UdVbQ4o0SXWgegOhSu8rLj2ROyvMMc6qa5wiTqJSvjfwMgCMHhDSqD 766zzB14499A1eCxeOEi1OoPz3J7Q9T1Wh+pgZT0sWr6uckHi5swc5Bm5KO3JmtdfYkj g0xNmu33vjnMruIEILUohMK/6ag2VBpFyCgq+k2GvkjqChQeqIGizwemTSmTEuMj4ZYs rLndrRqXaAC8gkD4F1MUoPlrb53UhRyoPtz+q5vKRP9Mgr7yIGIrpsuiFwdNF4c8zbIk To5Q== 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; bh=saNlXTXB51vCTSXiZxahbXz4v7+9GH/MAa0h7DJY6Cs=; b=07f9pvzkVSCl3YszUe+W5UxhkXbvE57bZEavRaokvnlgjshATyj8/T65DpbvvLcb08 dsjYq/AL/fvgKgHIBmodVJvDDxun1D5+dZ5K1YiY9JohP0Z+D6d6WZhVHzEL40btnYos xUyhLrN8LB1iix2xMsL8DlnSSVmDdjpQU4Z93D3AXADuQTze6RHkhwpxPM5dKhttLWIv dZBulqQpsXxtkv4RbWURMxH3uLkhGg3atKY3lx0SwdGzaPPjPWhKdf0+UPQPMFZZz3EH b/uHLJKcvj2YyXF0L+Zc8YITgLczepTfulFBvuUbEteTj1gX5fIepYRQ+ohelYhz6KQH /ADA== X-Gm-Message-State: ACgBeo22XE60NPsf6LlVKcNp+2DtWCACOGcm0okE4XTHfd840O3rSY5a HDrRbow8b71OZE3vFlWBtuzKrw== X-Google-Smtp-Source: AA6agR5vjoTRwnjXdkJx3Cg8pAB0tbVog7lDt4rC5XIE2WKSmZnhbp64mkFAWZYK1yFvmH5MfnvTow== X-Received: by 2002:a05:600c:600b:b0:3a5:b811:e7fc with SMTP id az11-20020a05600c600b00b003a5b811e7fcmr77002wmb.190.1660140464270; Wed, 10 Aug 2022 07:07:44 -0700 (PDT) Received: from localhost.localdomain (32.31.102.84.rev.sfr.net. [84.102.31.32]) by smtp.gmail.com with ESMTPSA id o15-20020adfcf0f000000b0021d6a520ce9sm16258229wrj.47.2022.08.10.07.07.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Aug 2022 07:07:43 -0700 (PDT) From: Julien Panis To: vilhelm.gray@gmail.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, mranostay@ti.com, Julien Panis Subject: [PATCH v4 2/3] Documentation: ABI: add sysfs-bus-counter-ecap Date: Wed, 10 Aug 2022 16:07:23 +0200 Message-Id: <20220810140724.182389-3-jpanis@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220810140724.182389-1-jpanis@baylibre.com> References: <20220810140724.182389-1-jpanis@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" This commit adds an ABI file for TI ECAP used in capture operating mode. Signed-off-by: Julien Panis --- .../ABI/testing/sysfs-bus-counter-ecap | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-ecap diff --git a/Documentation/ABI/testing/sysfs-bus-counter-ecap b/Documentati= on/ABI/testing/sysfs-bus-counter-ecap new file mode 100644 index 000000000000..ca530a6806de --- /dev/null +++ b/Documentation/ABI/testing/sysfs-bus-counter-ecap @@ -0,0 +1,64 @@ +What: /sys/bus/counter/devices/counter0/signal0/polarity1 +What: /sys/bus/counter/devices/counter0/signal0/polarity2 +What: /sys/bus/counter/devices/counter0/signal0/polarity3 +What: /sys/bus/counter/devices/counter0/signal0/polarity4 +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + ECAP module includes 4 timestamp capture registers. + For all 4 sequenced timestamp capture events (1->2->3->4->1->...), + edge polarity can be selected. Then, each capture register can be + tuned to capture event by either: + + - "rising" + - "falling" + + Reading returns current trigger polarity. + + Writing value before enabling capture sets trigger polarity. + +What: /sys/bus/counter/devices/counter0/signal0/polarity1_available +What: /sys/bus/counter/devices/counter0/signal0/polarity2_available +What: /sys/bus/counter/devices/counter0/signal0/polarity3_available +What: /sys/bus/counter/devices/counter0/signal0/polarity4_available +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + Discrete set of available values for the respective polarity X + configuration are listed in this file. Values are delimited by + newline characters. + +What: /sys/bus/counter/devices/counter0/count0/enable +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + Whether ECAP is enabled. Valid attribute values are boolean. + + This attribute is intended to serve as a start/stop mechanism + for ECAP. + +What: /sys/bus/counter/devices/counter0/count0/count +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + Read-only attribute that indicates the current base counter value. + +What: /sys/bus/counter/devices/counter0/count0/capture1 +What: /sys/bus/counter/devices/counter0/count0/capture2 +What: /sys/bus/counter/devices/counter0/count0/capture3 +What: /sys/bus/counter/devices/counter0/count0/capture4 +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + Read-only attributes that indicate the last timestamp captured + for the respective capture X register. + +What: /sys/bus/counter/devices/counter0/count0/capture1_component_id +What: /sys/bus/counter/devices/counter0/count0/capture2_component_id +What: /sys/bus/counter/devices/counter0/count0/capture3_component_id +What: /sys/bus/counter/devices/counter0/count0/capture4_component_id +KernelVersion: 5.19 +Contact: jpanis@baylibre.com +Description: + Read-only attributes that indicate the component ID of the + respective extension or synapse. --=20 2.25.1 From nobody Mon Apr 13 12:01:09 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 77742C19F2A for ; Wed, 10 Aug 2022 14:08:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232915AbiHJOH7 (ORCPT ); Wed, 10 Aug 2022 10:07:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45560 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232966AbiHJOHt (ORCPT ); Wed, 10 Aug 2022 10:07:49 -0400 Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD3CE6E2FD for ; Wed, 10 Aug 2022 07:07:47 -0700 (PDT) Received: by mail-wm1-x333.google.com with SMTP id k17so996142wmr.2 for ; Wed, 10 Aug 2022 07:07:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20210112.gappssmtp.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc; bh=+VWp5YJoC57tT62ho/EPk96glNOHhP7a8oq/PqvtVMc=; b=bNtuJrLQuQbRW86cL7f03yzt5BJdMFqh+gMOPPiiJAuDVnsSigCEl9wnE0btkBHh+0 5tYcbf2d/sc4++enb0FrlojdZz5xlLZ/v1bHWhrS/J3vJ9UlmUUVAVvJZlSkfFPaNxpg 9o/Wnl1Rg+meWo5vfPLoZN4Pqz3kZYR5Y55Ja6LO9QwhMG8ERnepzZ4PHMAqGd+B8RZ1 rqopymKguq0aL/ZlUUE+aS/HUW+V2BzrjzydaE3Hf82j9WPgihorokmmQsfufVp/SjYR Cj/N0wVLsHQpvGtULe6c0D0TUlTZVvRaEYnFytSTdUe1LkFArXH9xHqAe3a2FaFQpg6E ljXg== 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; bh=+VWp5YJoC57tT62ho/EPk96glNOHhP7a8oq/PqvtVMc=; b=0UMqHuApPzsK1K1YB6mNbG5igdPviqEi+WVKnnxrqF036Q7rmv9ahxDpEc28E/16Xa OUC0uyugw86va5zkfe//rpm0bonXxnywFB1FMBlpPN6aat0Qw5zfcrC2Xxp3kyqZdpQj YVRlXlQubse1HRZbNjTStE1xh3yvcYfPxntUotUTo3hZiLPFwkxc373xiVoW1WR5Owc3 SgqWPynd/+aUqtXBV6asjkHRkCCaltD1V4C+nXoVFp5A7dZL5f4Cz2ELRPp4LnmherKX YBygFRgXzwGlb+bo7txW8jvaWs+o8JLnNYapw0jAB9U6D79+ZXefzihOxyZU1+0xzdF8 gcaQ== X-Gm-Message-State: ACgBeo3yL/sEI2W54k4aY4ubIQWLQvD9QQRZPFgzSSWwmfBwxZKfq1eu XPg3TS/rDFZWghXfBvzSqm5qeg== X-Google-Smtp-Source: AA6agR74AKmCyHb8DU+RAO/kXwjbCyVQ39TmgPKE8vv0Hz5gpWmd79XnLBcgjVxvEIYCqvJjWL9pSA== X-Received: by 2002:a05:600c:3790:b0:3a5:435d:b2d3 with SMTP id o16-20020a05600c379000b003a5435db2d3mr2696564wmr.134.1660140466190; Wed, 10 Aug 2022 07:07:46 -0700 (PDT) Received: from localhost.localdomain (32.31.102.84.rev.sfr.net. [84.102.31.32]) by smtp.gmail.com with ESMTPSA id o15-20020adfcf0f000000b0021d6a520ce9sm16258229wrj.47.2022.08.10.07.07.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Aug 2022 07:07:45 -0700 (PDT) From: Julien Panis To: vilhelm.gray@gmail.com, robh+dt@kernel.org, krzysztof.kozlowski+dt@linaro.org Cc: linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org, devicetree@vger.kernel.org, mranostay@ti.com, Julien Panis Subject: [PATCH v4 3/3] counter: capture-tiecap: capture driver support for ECAP Date: Wed, 10 Aug 2022 16:07:24 +0200 Message-Id: <20220810140724.182389-4-jpanis@baylibre.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220810140724.182389-1-jpanis@baylibre.com> References: <20220810140724.182389-1-jpanis@baylibre.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" ECAP hardware on AM62x SoC supports capture feature. It can be used to timestamp events (falling/rising edges) detected on signal input pin. This commit adds capture driver support for ECAP hardware on AM62x SoC. In the ECAP hardware, capture pin can also be configured to be in PWM mode. Current implementation only supports capture operating mode. Hardware also supports timebase sync between multiple instances, but this driver supports simple independent capture functionality. Signed-off-by: Julien Panis --- drivers/counter/Kconfig | 14 + drivers/counter/Makefile | 1 + drivers/counter/capture-tiecap.c | 634 +++++++++++++++++++++++++++++++ include/uapi/linux/counter.h | 2 + 4 files changed, 651 insertions(+) create mode 100644 drivers/counter/capture-tiecap.c diff --git a/drivers/counter/Kconfig b/drivers/counter/Kconfig index 5edd155f1911..580640807a94 100644 --- a/drivers/counter/Kconfig +++ b/drivers/counter/Kconfig @@ -101,4 +101,18 @@ config INTEL_QEP To compile this driver as a module, choose M here: the module will be called intel-qep. =20 +config CAPTURE_TIECAP + tristate "TI eCAP capture driver" + depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX || ARCH_KEYSTONE || ARCH_= K3 || COMPILE_TEST + depends on HAS_IOMEM + help + Select this option to enable the Texas Instruments Enhanced Capture + (eCAP) driver in input mode. + + It can be used to timestamp events (falling/rising edges) detected + on signal input pin. + + To compile this driver as a module, choose M here: the module + will be called capture-tiecap. + endif # COUNTER diff --git a/drivers/counter/Makefile b/drivers/counter/Makefile index 8fde6c100ebc..7fac3e0985b5 100644 --- a/drivers/counter/Makefile +++ b/drivers/counter/Makefile @@ -14,3 +14,4 @@ obj-$(CONFIG_TI_EQEP) +=3D ti-eqep.o obj-$(CONFIG_FTM_QUADDEC) +=3D ftm-quaddec.o obj-$(CONFIG_MICROCHIP_TCB_CAPTURE) +=3D microchip-tcb-capture.o obj-$(CONFIG_INTEL_QEP) +=3D intel-qep.o +obj-$(CONFIG_CAPTURE_TIECAP) +=3D capture-tiecap.o diff --git a/drivers/counter/capture-tiecap.c b/drivers/counter/capture-tie= cap.c new file mode 100644 index 000000000000..0601c65ef203 --- /dev/null +++ b/drivers/counter/capture-tiecap.c @@ -0,0 +1,634 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * ECAP Capture driver + * + * Copyright (C) 2022 Julien Panis + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ECAP_DRV_NAME "ecap" + +/* Registers */ +#define ECAP_NB_CAP 4 + +#define ECAP_TSCNT_REG 0x00 + +#define ECAP_CAP_REG(i) (((i) << 2) + 0x08) + +#define ECAP_ECCTL_REG 0x28 +#define ECAP_CAPPOL_BIT(i) BIT((i) << 1) +#define ECAP_EV_MODE_MASK GENMASK(7, 0) +#define ECAP_CAPLDEN_BIT BIT(8) +#define ECAP_CONT_ONESHT_BIT BIT(16) +#define ECAP_STOPVALUE_MASK GENMASK(18, 17) +#define ECAP_REARM_RESET_BIT BIT(19) +#define ECAP_TSCNTSTP_BIT BIT(20) +#define ECAP_SYNCO_DIS_MASK GENMASK(23, 22) +#define ECAP_CAP_APWM_BIT BIT(25) +#define ECAP_ECCTL_EN_MASK (ECAP_CAPLDEN_BIT | ECAP_TSCNTSTP_BIT) +#define ECAP_ECCTL_CFG_MASK (ECAP_SYNCO_DIS_MASK | ECAP_STOPVALUE_MASK \ + | ECAP_ECCTL_EN_MASK | ECAP_REARM_RESET_BIT \ + | ECAP_CAP_APWM_BIT | ECAP_CONT_ONESHT_BIT) + +#define ECAP_ECINT_EN_FLG_REG 0x2c +#define ECAP_NB_CEVT (ECAP_NB_CAP + 1) +#define ECAP_CEVT_EN_MASK GENMASK(ECAP_NB_CEVT, ECAP_NB_CAP) +#define ECAP_CEVT_FLG_BIT(i) BIT((i) + 17) + +#define ECAP_ECINT_CLR_FRC_REG 0x30 +#define ECAP_INT_CLR_BIT BIT(0) +#define ECAP_CEVT_CLR_BIT(i) BIT((i) + 1) +#define ECAP_CEVT_CLR_MASK GENMASK(ECAP_NB_CEVT, 0) + +#define ECAP_PID_REG 0x5c + +/* + * Event modes + * One bit for each CAPx register : 1 =3D falling edge / 0 =3D rising edge + * e.g. mode =3D 13 =3D 0xd =3D 0b1101 + * -> falling edge for CAP1-3-4 / rising edge for CAP2 + */ +#define ECAP_EV_MODE_BIT(i) BIT(i) + +/* ECAP input */ +#define ECAP_SIGNAL 0 + +static const struct regmap_config ecap_cnt_regmap_config =3D { + .reg_bits =3D 32, + .reg_stride =3D 4, + .val_bits =3D 32, + .max_register =3D ECAP_PID_REG, +}; + +/** + * struct ecap_cnt_dev - device private data structure + * @enabled: device state + * @clk: device clock + * @clk_rate: device clock rate + * @regmap: device register map + * @elapsed_time: elapsed time since capture start + * @lock: synchronization lock to prevent race conditions when com= puting times + * @pm_ctx: device context for PM operations + */ +struct ecap_cnt_dev { + bool enabled; + struct clk *clk; + unsigned long clk_rate; + struct regmap *regmap; + __aligned_u64 elapsed_time; + spinlock_t lock; + struct { + u8 ev_mode; + unsigned int time_cntr; + } pm_ctx; +}; + +static u8 ecap_cnt_capture_get_evmode(struct counter_device *counter) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + u8 ev_mode =3D 0; + unsigned int regval; + int i; + + pm_runtime_get_sync(counter->parent); + regmap_read(ecap_dev->regmap, ECAP_ECCTL_REG, ®val); + pm_runtime_put_sync(counter->parent); + + for (i =3D 0 ; i < ECAP_NB_CAP ; i++) { + if (regval & ECAP_CAPPOL_BIT(i)) + ev_mode |=3D ECAP_EV_MODE_BIT(i); + } + + return ev_mode; +} + +static void ecap_cnt_capture_set_evmode(struct counter_device *counter, u8= ev_mode) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + unsigned int regval =3D 0; + int i; + + for (i =3D 0 ; i < ECAP_NB_CAP ; i++) { + if (ev_mode & ECAP_EV_MODE_BIT(i)) + regval |=3D ECAP_CAPPOL_BIT(i); + } + + pm_runtime_get_sync(counter->parent); + regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_EV_MODE_MASK, r= egval); + pm_runtime_put_sync(counter->parent); +} + +static void ecap_cnt_capture_enable(struct counter_device *counter, bool r= earm) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + unsigned int regval; + + pm_runtime_get_sync(counter->parent); + + /* Enable interrupts on events */ + regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG, + ECAP_CEVT_EN_MASK, ECAP_CEVT_EN_MASK); + + /* Run counter */ + regval =3D ECAP_SYNCO_DIS_MASK | ECAP_STOPVALUE_MASK | ECAP_ECCTL_EN_MASK; + if (rearm) { + ecap_dev->elapsed_time =3D 0; + regmap_write(ecap_dev->regmap, ECAP_TSCNT_REG, 0); + regval |=3D ECAP_REARM_RESET_BIT; + } + regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_ECCTL_CFG_MASK,= regval); +} + +static void ecap_cnt_capture_disable(struct counter_device *counter) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + + /* Disable interrupts on events */ + regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG, ECAP_CEVT_EN_= MASK, 0); + + /* Stop counter */ + regmap_update_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_ECCTL_EN_MASK, = 0); + + pm_runtime_put_sync(counter->parent); +} + +static int ecap_cnt_count_get_ns(struct counter_device *counter, unsigned = int reg, u64 *val) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + unsigned int regval; + unsigned long flags; + + pm_runtime_get_sync(counter->parent); + spin_lock_irqsave(&ecap_dev->lock, flags); + + /* time_ns =3D 10^9 * (time_cycles + time_cumul) / clk_rate */ + regmap_read(ecap_dev->regmap, reg, ®val); + *val =3D (regval + ecap_dev->elapsed_time) * NSEC_PER_SEC; + do_div(*val, ecap_dev->clk_rate); + + spin_unlock_irqrestore(&ecap_dev->lock, flags); + pm_runtime_put_sync(counter->parent); + + return 0; +} + +static inline int ecap_cnt_count_read(struct counter_device *counter, + struct counter_count *count, + u64 *val) +{ + return ecap_cnt_count_get_ns(counter, ECAP_TSCNT_REG, val); +} + +static int ecap_cnt_function_read(struct counter_device *counter, + struct counter_count *count, + enum counter_function *function) +{ + *function =3D COUNTER_FUNCTION_INCREASE; + + return 0; +} + +static int ecap_cnt_action_read(struct counter_device *counter, + struct counter_count *count, + struct counter_synapse *synapse, + enum counter_synapse_action *action) +{ + *action =3D COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + + return 0; +} + +static int ecap_cnt_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + struct counter_event_node *event_node; + + if (watch->channel || watch->event !=3D COUNTER_EVENT_CAPTURE) + return -EINVAL; + + list_for_each_entry(event_node, &counter->next_events_list, l) + if (watch->component.type !=3D COUNTER_COMPONENT_EXTENSION || + watch->component.scope !=3D COUNTER_SCOPE_COUNT || + watch->component.parent || + watch->component.id >=3D ECAP_NB_CAP) + return -EINVAL; + + return 0; +} + +static int ecap_cnt_enable_read(struct counter_device *counter, + struct counter_count *count, + u8 *enable) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + + *enable =3D ecap_dev->enabled; + + return 0; +} + +static int ecap_cnt_enable_write(struct counter_device *counter, + struct counter_count *count, + u8 enable) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + + if (enable > 1) + return -EINVAL; + if (enable =3D=3D ecap_dev->enabled) + return 0; + if (enable) + ecap_cnt_capture_enable(counter, true); + else + ecap_cnt_capture_disable(counter); + ecap_dev->enabled =3D enable; + + return 0; +} + +static int ecap_cnt_cap_get_pol(struct counter_device *counter, + struct counter_signal *signal, + u32 *pol, u8 inst) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + + pm_runtime_get_sync(counter->parent); + *pol =3D regmap_test_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_B= IT(inst)); + pm_runtime_put_sync(counter->parent); + + return 0; +} + +static int ecap_cnt_cap_set_pol(struct counter_device *counter, + struct counter_signal *signal, + u32 pol, u8 inst) +{ + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter); + + if (ecap_dev->enabled) + return -EBUSY; + if (pol > 1) + return -EINVAL; + + pm_runtime_get_sync(counter->parent); + if (pol) + regmap_set_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_BIT(inst)); + else + regmap_clear_bits(ecap_dev->regmap, ECAP_ECCTL_REG, ECAP_CAPPOL_BIT(inst= )); + pm_runtime_put_sync(counter->parent); + + return 0; +} + +static inline int ecap_cnt_cap_read(struct counter_device *counter, + struct counter_count *count, + u64 *cap, u8 inst) +{ + return ecap_cnt_count_get_ns(counter, ECAP_CAP_REG(inst), cap); +} + +static inline int ecap_cnt_cap1_get_pol(struct counter_device *counter, + struct counter_signal *signal, u32 *pol) +{ + return ecap_cnt_cap_get_pol(counter, signal, pol, 0); +} + +static inline int ecap_cnt_cap2_get_pol(struct counter_device *counter, + struct counter_signal *signal, u32 *pol) +{ + return ecap_cnt_cap_get_pol(counter, signal, pol, 1); +} + +static inline int ecap_cnt_cap3_get_pol(struct counter_device *counter, + struct counter_signal *signal, u32 *pol) +{ + return ecap_cnt_cap_get_pol(counter, signal, pol, 2); +} + +static inline int ecap_cnt_cap4_get_pol(struct counter_device *counter, + struct counter_signal *signal, u32 *pol) +{ + return ecap_cnt_cap_get_pol(counter, signal, pol, 3); +} + +static inline int ecap_cnt_cap1_set_pol(struct counter_device *counter, + struct counter_signal *signal, u32 pol) +{ + return ecap_cnt_cap_set_pol(counter, signal, pol, 0); +} + +static inline int ecap_cnt_cap2_set_pol(struct counter_device *counter, + struct counter_signal *signal, u32 pol) +{ + return ecap_cnt_cap_set_pol(counter, signal, pol, 1); +} + +static inline int ecap_cnt_cap3_set_pol(struct counter_device *counter, + struct counter_signal *signal, u32 pol) +{ + return ecap_cnt_cap_set_pol(counter, signal, pol, 2); +} + +static inline int ecap_cnt_cap4_set_pol(struct counter_device *counter, + struct counter_signal *signal, u32 pol) +{ + return ecap_cnt_cap_set_pol(counter, signal, pol, 3); +} + +static inline int ecap_cnt_cap1_read(struct counter_device *counter, + struct counter_count *count, u64 *cap) +{ + return ecap_cnt_cap_read(counter, count, cap, 0); +} + +static inline int ecap_cnt_cap2_read(struct counter_device *counter, + struct counter_count *count, u64 *cap) +{ + return ecap_cnt_cap_read(counter, count, cap, 1); +} + +static inline int ecap_cnt_cap3_read(struct counter_device *counter, + struct counter_count *count, u64 *cap) +{ + return ecap_cnt_cap_read(counter, count, cap, 2); +} + +static inline int ecap_cnt_cap4_read(struct counter_device *counter, + struct counter_count *count, u64 *cap) +{ + return ecap_cnt_cap_read(counter, count, cap, 3); +} + +static const struct counter_ops ecap_cnt_ops =3D { + .count_read =3D ecap_cnt_count_read, + .function_read =3D ecap_cnt_function_read, + .action_read =3D ecap_cnt_action_read, + .watch_validate =3D ecap_cnt_watch_validate, +}; + +static const enum counter_function ecap_cnt_functions[] =3D { + COUNTER_FUNCTION_INCREASE, +}; + +static const enum counter_synapse_action ecap_cnt_actions[] =3D { + COUNTER_SYNAPSE_ACTION_BOTH_EDGES, +}; + +static const char *const ecap_cnt_cap_polarities[] =3D { + "rising", + "falling", +}; + +static DEFINE_COUNTER_ENUM(ecap_cnt_cap_avail_pol, ecap_cnt_cap_polarities= ); + +static struct counter_comp ecap_cnt_signal_ext[] =3D { + COUNTER_COMP_SIGNAL_ENUM("polarity1", ecap_cnt_cap1_get_pol, + ecap_cnt_cap1_set_pol, ecap_cnt_cap_avail_pol), + COUNTER_COMP_SIGNAL_ENUM("polarity2", ecap_cnt_cap2_get_pol, + ecap_cnt_cap2_set_pol, ecap_cnt_cap_avail_pol), + COUNTER_COMP_SIGNAL_ENUM("polarity3", ecap_cnt_cap3_get_pol, + ecap_cnt_cap3_set_pol, ecap_cnt_cap_avail_pol), + COUNTER_COMP_SIGNAL_ENUM("polarity4", ecap_cnt_cap4_get_pol, + ecap_cnt_cap4_set_pol, ecap_cnt_cap_avail_pol), +}; + +static struct counter_signal ecap_cnt_signals[] =3D { + { + .id =3D ECAP_SIGNAL, + .name =3D "ECAPSIG", + .ext =3D ecap_cnt_signal_ext, + .num_ext =3D ARRAY_SIZE(ecap_cnt_signal_ext), + }, +}; + +static struct counter_synapse ecap_cnt_synapses[] =3D { + { + .actions_list =3D ecap_cnt_actions, + .num_actions =3D ARRAY_SIZE(ecap_cnt_actions), + .signal =3D &ecap_cnt_signals[ECAP_SIGNAL], + }, +}; + +static struct counter_comp ecap_cnt_count_ext[] =3D { + COUNTER_COMP_COUNT_U64("capture1", ecap_cnt_cap1_read, NULL), + COUNTER_COMP_COUNT_U64("capture2", ecap_cnt_cap2_read, NULL), + COUNTER_COMP_COUNT_U64("capture3", ecap_cnt_cap3_read, NULL), + COUNTER_COMP_COUNT_U64("capture4", ecap_cnt_cap4_read, NULL), + COUNTER_COMP_ENABLE(ecap_cnt_enable_read, ecap_cnt_enable_write), +}; + +static struct counter_count ecap_cnt_counts[] =3D { + { + .id =3D 0, + .name =3D "ECAPCNT", + .functions_list =3D ecap_cnt_functions, + .num_functions =3D ARRAY_SIZE(ecap_cnt_functions), + .synapses =3D ecap_cnt_synapses, + .num_synapses =3D ARRAY_SIZE(ecap_cnt_synapses), + .ext =3D ecap_cnt_count_ext, + .num_ext =3D ARRAY_SIZE(ecap_cnt_count_ext), + }, +}; + +static irqreturn_t ecap_cnt_isr(int irq, void *dev_id) +{ + struct counter_device *counter_dev =3D dev_id; + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter_dev); + unsigned int clr =3D 0; + unsigned int flg; + int i; + unsigned long flags; + + regmap_read(ecap_dev->regmap, ECAP_ECINT_EN_FLG_REG, &flg); + + for (i =3D ECAP_NB_CAP - 1 ; i < ECAP_NB_CEVT ; i++) { + if (flg & ECAP_CEVT_FLG_BIT(i)) { + if (i < ECAP_NB_CAP) { + /* Input signal edge detected on last CAP (CAP4) */ + counter_push_event(counter_dev, COUNTER_EVENT_CAPTURE, 0); + } else { + /* Counter overflow */ + spin_lock_irqsave(&ecap_dev->lock, flags); + ecap_dev->elapsed_time +=3D (u64)U32_MAX + 1; + spin_unlock_irqrestore(&ecap_dev->lock, flags); + } + + clr |=3D ECAP_CEVT_CLR_BIT(i); + } + } + + clr |=3D ECAP_INT_CLR_BIT; + regmap_update_bits(ecap_dev->regmap, ECAP_ECINT_CLR_FRC_REG, ECAP_CEVT_CL= R_MASK, clr); + + return IRQ_HANDLED; +} + +static void ecap_cnt_clk_disable(void *clk) +{ + clk_disable_unprepare(clk); +} + +static int ecap_cnt_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ecap_cnt_dev *ecap_dev; + struct counter_device *counter_dev; + void __iomem *mmio_base; + int ret; + + counter_dev =3D devm_counter_alloc(dev, sizeof(*ecap_dev)); + if (IS_ERR(counter_dev)) + return PTR_ERR(counter_dev); + + counter_dev->name =3D ECAP_DRV_NAME; + counter_dev->parent =3D dev; + counter_dev->ops =3D &ecap_cnt_ops; + counter_dev->signals =3D ecap_cnt_signals; + counter_dev->num_signals =3D ARRAY_SIZE(ecap_cnt_signals); + counter_dev->counts =3D ecap_cnt_counts; + counter_dev->num_counts =3D ARRAY_SIZE(ecap_cnt_counts); + + ecap_dev =3D counter_priv(counter_dev); + + ecap_dev->clk =3D devm_clk_get(dev, "fck"); + if (IS_ERR(ecap_dev->clk)) + return dev_err_probe(dev, PTR_ERR(ecap_dev->clk), "failed to get clock\n= "); + + ret =3D clk_prepare_enable(ecap_dev->clk); + if (ret) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + + ret =3D devm_add_action_or_reset(dev, ecap_cnt_clk_disable, ecap_dev->clk= ); + if (ret) { + dev_err(dev, "failed to add clock disable action\n"); + return ret; + } + + ecap_dev->clk_rate =3D clk_get_rate(ecap_dev->clk); + if (!ecap_dev->clk_rate) { + dev_err(dev, "failed to get clock rate\n"); + return -EINVAL; + } + + mmio_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mmio_base)) + return PTR_ERR(mmio_base); + + ecap_dev->regmap =3D devm_regmap_init_mmio(dev, mmio_base, &ecap_cnt_regm= ap_config); + if (IS_ERR(ecap_dev->regmap)) + return dev_err_probe(dev, PTR_ERR(ecap_dev->regmap), "failed to init reg= map\n"); + + spin_lock_init(&ecap_dev->lock); + + ret =3D platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "failed to get irq\n"); + return ret; + } + + ret =3D devm_request_irq(dev, ret, ecap_cnt_isr, 0, pdev->name, counter_d= ev); + if (ret) { + dev_err(dev, "failed to request irq\n"); + return ret; + } + + platform_set_drvdata(pdev, counter_dev); + pm_runtime_enable(dev); + + ecap_dev->enabled =3D 0; + ecap_cnt_capture_set_evmode(counter_dev, 0); + + ret =3D devm_counter_add(dev, counter_dev); + if (ret) { + dev_err(dev, "failed to add counter\n"); + pm_runtime_disable(dev); + } + + return ret; +} + +static int ecap_cnt_remove(struct platform_device *pdev) +{ + struct counter_device *counter_dev =3D platform_get_drvdata(pdev); + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter_dev); + + if (ecap_dev->enabled) + ecap_cnt_capture_disable(counter_dev); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int ecap_cnt_suspend(struct device *dev) +{ + struct counter_device *counter_dev =3D dev_get_drvdata(dev); + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter_dev); + + /* If eCAP is running, stop capture then save timestamp counter */ + if (ecap_dev->enabled) { + ecap_cnt_capture_disable(counter_dev); + + pm_runtime_get_sync(dev); + regmap_read(ecap_dev->regmap, ECAP_TSCNT_REG, &ecap_dev->pm_ctx.time_cnt= r); + pm_runtime_put_sync(dev); + } + + ecap_dev->pm_ctx.ev_mode =3D ecap_cnt_capture_get_evmode(counter_dev); + + return 0; +} + +static int ecap_cnt_resume(struct device *dev) +{ + struct counter_device *counter_dev =3D dev_get_drvdata(dev); + struct ecap_cnt_dev *ecap_dev =3D counter_priv(counter_dev); + + ecap_cnt_capture_set_evmode(counter_dev, ecap_dev->pm_ctx.ev_mode); + + /* If eCAP was running, restore timestamp counter then run capture */ + if (ecap_dev->enabled) { + pm_runtime_get_sync(dev); + regmap_write(ecap_dev->regmap, ECAP_TSCNT_REG, ecap_dev->pm_ctx.time_cnt= r); + pm_runtime_put_sync(dev); + + ecap_cnt_capture_enable(counter_dev, false); + } + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(ecap_cnt_pm_ops, ecap_cnt_suspend, ecap_cn= t_resume); + +static const struct of_device_id ecap_cnt_of_match[] =3D { + { .compatible =3D "ti,am62-ecap-capture" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ecap_cnt_of_match); + +static struct platform_driver ecap_cnt_driver =3D { + .probe =3D ecap_cnt_probe, + .remove =3D ecap_cnt_remove, + .driver =3D { + .name =3D "ecap-capture", + .of_match_table =3D ecap_cnt_of_match, + .pm =3D pm_sleep_ptr(&ecap_cnt_pm_ops), + }, +}; +module_platform_driver(ecap_cnt_driver); + +MODULE_DESCRIPTION("ECAP Capture driver"); +MODULE_AUTHOR("Julien Panis "); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h index 96c5ffd368ad..4c5372c6f2a3 100644 --- a/include/uapi/linux/counter.h +++ b/include/uapi/linux/counter.h @@ -63,6 +63,8 @@ enum counter_event_type { COUNTER_EVENT_INDEX, /* State of counter is changed */ COUNTER_EVENT_CHANGE_OF_STATE, + /* Count value is captured */ + COUNTER_EVENT_CAPTURE, }; =20 /** --=20 2.25.1