From patchwork Tue Aug 29 13:40:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369099 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 921D6C83F12 for ; Tue, 29 Aug 2023 14:58:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S237121AbjH2O62 (ORCPT ); Tue, 29 Aug 2023 10:58:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44478 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237149AbjH2O6Q (ORCPT ); Tue, 29 Aug 2023 10:58:16 -0400 Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [185.132.182.106]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 92594BC; Tue, 29 Aug 2023 07:58:12 -0700 (PDT) Received: from pps.filterd (m0288072.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TBwgZB019602; Tue, 29 Aug 2023 15:40:56 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=YRG7/1LKonbXReVVMUzYv6d5sYbYplVCZHB7ICikVjE=; b=b4 TV0rmKjy7gKGpMJIzHDi1cjDRl3JOpB2Gmnc+KCywe+vrB1NrwlHDu8KIFE1rZ2s j3CjqacchVgAdIx9P6TWIoirNcKPdIC8u6ujH23Ppc5YV55TwseKaxBlYtXgVoiV Vxg232uMKYSFDq1hAaC3mA8Xszj0tRe02LF8H5E/ywpf9XTrNP6xe0k5YGbufY/v TqncmDOjC5OV1EbCkk2wojCFSOeEIiqcj2Wf2mDrCw81ETCUfAsbtq/7SYCEkIXs AWNDJ8Dy8XX/mVpSMUFqXHHJPMp/SuuntJgiFqHPEanMvx+Ua/3W6XsZ7DIunjAM s4FlvpxOuKHwQgPt0XTg== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq6tfmchf-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:40:56 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id DBB7E100057; Tue, 29 Aug 2023 15:40:55 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id CBC612207DB; Tue, 29 Aug 2023 15:40:55 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:40:54 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 1/8] counter: chrdev: fix getting array extensions Date: Tue, 29 Aug 2023 15:40:22 +0200 Message-ID: <20230829134029.2402868-2-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org When trying to watch a component array extension, and the array isn't the first extended element, it fails as the type comparison is always done on the 1st element. Fix it by indexing the 'ext' array. Example on a dummy struct counter_comp: static struct counter_comp dummy[] = { COUNTER_COMP_DIRECTION(..), ..., COUNTER_COMP_ARRAY_CAPTURE(...), }; static struct counter_count dummy_cnt = { ... .ext = dummy, .num_ext = ARRAY_SIZE(dummy), } Currently, counter_get_ext() returns -EINVAL when trying to add a watch event on one of the capture array element in such example. Fixes: d2011be1e22f ("counter: Introduce the COUNTER_COMP_ARRAY component type") Signed-off-by: Fabrice Gasnier --- drivers/counter/counter-chrdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c index 80acdf62794a..afc94d0062b1 100644 --- a/drivers/counter/counter-chrdev.c +++ b/drivers/counter/counter-chrdev.c @@ -247,8 +247,8 @@ static int counter_get_ext(const struct counter_comp *const ext, if (*id == component_id) return 0; - if (ext->type == COUNTER_COMP_ARRAY) { - element = ext->priv; + if (ext[*ext_idx].type == COUNTER_COMP_ARRAY) { + element = ext[*ext_idx].priv; if (component_id - *id < element->length) return 0; From patchwork Tue Aug 29 13:40:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369050 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 25500C83F12 for ; Tue, 29 Aug 2023 14:13:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232584AbjH2ONR (ORCPT ); Tue, 29 Aug 2023 10:13:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52638 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236883AbjH2OMw (ORCPT ); Tue, 29 Aug 2023 10:12:52 -0400 Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DC69A1BC; Tue, 29 Aug 2023 07:12:48 -0700 (PDT) Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 37TC82RY021636; Tue, 29 Aug 2023 15:40:59 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=lxhEdzurpdkE9C1wxBVksd7Z8O/aa/66F4a3dEvFca0=; b=Al N1ipsgL8FqTCsJkQ6mW+WhqF1XjKDp5Ju+0RwDsM+/UflBpvBMd0IWaR9feRfDaQ rMyLFr03BLwIE9Nbhuyg3YAhJeJSDXnnPXOXkWvcVwB5zbWT5sfzF2RSvhbh9TfH ejh1JoSbkY09zszxliUsvKdzmsWLEE0D9hRdbSPMIQmpC6PDJcEbP8sRSa5yakNE 9Np7J6ss5dv3iJfcDI7BMVg/V6LXsPRA7s9MnertKAKN0Nn7Vd8suW09MA0CLeUg koaLkPIrJhIVmprP3U47maFfJJXX2eXKjH89suWdawRWLF3y/bHa33+8SPyapd3l GXFDvNmLFuHWzg2ZMVoA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq6h44p22-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:40:59 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A5ADE100057; Tue, 29 Aug 2023 15:40:58 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 9F04E2207DB; Tue, 29 Aug 2023 15:40:58 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:40:55 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 2/8] counter: chrdev: remove a typo in header file comment Date: Tue, 29 Aug 2023 15:40:23 +0200 Message-ID: <20230829134029.2402868-3-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Replace COUNTER_COUNT_SCOPE that doesn't exist by the defined COUNTER_SCOPE_COUNT. Signed-off-by: Fabrice Gasnier --- include/uapi/linux/counter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/counter.h b/include/uapi/linux/counter.h index fc248ef00e86..008a691c254b 100644 --- a/include/uapi/linux/counter.h +++ b/include/uapi/linux/counter.h @@ -38,7 +38,7 @@ enum counter_scope { * * For example, if the Count 2 ceiling extension of Counter device 4 is desired, * set type equal to COUNTER_COMPONENT_EXTENSION, scope equal to - * COUNTER_COUNT_SCOPE, parent equal to 2, and id equal to the value provided by + * COUNTER_SCOPE_COUNT, parent equal to 2, and id equal to the value provided by * the respective /sys/bus/counter/devices/counter4/count2/ceiling_component_id * sysfs attribute. */ From patchwork Tue Aug 29 13:40:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369092 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 C4E8FC71153 for ; Tue, 29 Aug 2023 14:39:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236963AbjH2Oim (ORCPT ); Tue, 29 Aug 2023 10:38:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S237012AbjH2Oi1 (ORCPT ); Tue, 29 Aug 2023 10:38:27 -0400 Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [185.132.182.106]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E1A21AE; Tue, 29 Aug 2023 07:38:20 -0700 (PDT) Received: from pps.filterd (m0241204.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TBwku8022670; Tue, 29 Aug 2023 15:40:57 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=cjpw0qMq1w37JRDndUFptdySW5NdRruZOLIYm1872aA=; b=sO iabn6zFkWNuNYqYku/H7W0x2xXHoWpzWtEBlSqBI2B+AHZzveUP3ck8Ljj8pdetl crMUbtvpz+9u2GSH/+vCzUNFjuiLsnJUxCtuRXG/jnY0gjx9AvxeaofXfEj+i39s +awzKc8eky0mgzmxR0KtQqhJVg73Ehb45dKK2s7Ne3JEwdhtBSbx9LJdoSHdFOyl Cpp8GT5bJaqvPS6cIpObFjLD8f5DvYfiIamm6ZsTR2yAeze2QcPS4+uxb/eh9bRB p7Okon5Ntdspf2rejeTkW1+7uNcvjLyylEX+BbOzJQ6aDyLt8X4H+anfknE/F6sP 1N0VJ+Y3/WziGBFuxwOg== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq8qwc3jc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:40:57 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id E10D1100057; Tue, 29 Aug 2023 15:40:56 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id D59DD2207DB; Tue, 29 Aug 2023 15:40:56 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:40:56 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 3/8] tools/counter: add a flexible watch events tool Date: Tue, 29 Aug 2023 15:40:24 +0200 Message-ID: <20230829134029.2402868-4-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org This adds a new counter tool to be able to test various watch events. A flexible watch array can be populated from command line, each field may be tuned with a dedicated command line argument. Each argument can be repeated several times: each time it gets repeated, a corresponding new watch element is allocated. It also comes with a simple default watch (to monitor overflows), used when no watch parameters are provided. The print_usage() routine proposes another example, from the command line, which generates a 2 elements watch array, to monitor: - overflow events - capture events, on channel 3, that reads read captured data by specifying the component id (capture3_component_id being 7 here). Signed-off-by: Fabrice Gasnier --- tools/counter/Build | 1 + tools/counter/Makefile | 8 +- tools/counter/counter_watch_events.c | 348 +++++++++++++++++++++++++++ 3 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 tools/counter/counter_watch_events.c diff --git a/tools/counter/Build b/tools/counter/Build index 33f4a51d715e..4bbadb7ec93a 100644 --- a/tools/counter/Build +++ b/tools/counter/Build @@ -1 +1,2 @@ counter_example-y += counter_example.o +counter_watch_events-y += counter_watch_events.o diff --git a/tools/counter/Makefile b/tools/counter/Makefile index b2c2946f44c9..00e211edd768 100644 --- a/tools/counter/Makefile +++ b/tools/counter/Makefile @@ -14,7 +14,7 @@ MAKEFLAGS += -r override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -ALL_TARGETS := counter_example +ALL_TARGETS := counter_example counter_watch_events ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS)) all: $(ALL_PROGRAMS) @@ -31,6 +31,12 @@ $(OUTPUT)include/linux/counter.h: ../../include/uapi/linux/counter.h prepare: $(OUTPUT)include/linux/counter.h +COUNTER_WATCH_EVENTS := $(OUTPUT)counter_watch_events.o +$(COUNTER_WATCH_EVENTS): prepare FORCE + $(Q)$(MAKE) $(build)=counter_watch_events +$(OUTPUT)counter_watch_events: $(COUNTER_WATCH_EVENTS) + $(QUIET_LINK)$(CC) $(CFLAGS) $(LDFLAGS) $< -o $@ + COUNTER_EXAMPLE := $(OUTPUT)counter_example.o $(COUNTER_EXAMPLE): prepare FORCE $(Q)$(MAKE) $(build)=counter_example diff --git a/tools/counter/counter_watch_events.c b/tools/counter/counter_watch_events.c new file mode 100644 index 000000000000..7f73a1519d8e --- /dev/null +++ b/tools/counter/counter_watch_events.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Counter - Test various watch events in a userspace application + * inspired by counter_example.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +static struct counter_watch simple_watch[] = { + { + /* Component data: Count 0 count */ + .component.type = COUNTER_COMPONENT_COUNT, + .component.scope = COUNTER_SCOPE_COUNT, + .component.parent = 0, + /* Event type: Index */ + .event = COUNTER_EVENT_OVERFLOW_UNDERFLOW, + /* Device event channel 0 */ + .channel = 0, + }, +}; + +static int find_match_or_number_from_array(char *arg, const char * const str[], int sz, __u8 *val) +{ + unsigned int i; + char *dummy; + unsigned long idx; + int ret; + + for (i = 0; i < sz; i++) { + ret = strncmp(arg, str[i], strlen(str[i])); + if (!ret && strlen(str[i]) == strlen(arg)) { + *val = i; + return 0; + } + } + + /* fallback to number */ + idx = strtoul(optarg, &dummy, 10); + if (!errno) { + if (idx >= sz) + return -EINVAL; + *val = idx; + return 0; + } + + return -errno; +} + +static const char * const counter_event_type_name[] = { + "COUNTER_EVENT_OVERFLOW", + "COUNTER_EVENT_UNDERFLOW", + "COUNTER_EVENT_OVERFLOW_UNDERFLOW", + "COUNTER_EVENT_THRESHOLD", + "COUNTER_EVENT_INDEX", + "COUNTER_EVENT_CHANGE_OF_STATE", + "COUNTER_EVENT_CAPTURE", +}; + +static int counter_arg_to_event_type(char *arg, __u8 *event) +{ + return find_match_or_number_from_array(arg, counter_event_type_name, + ARRAY_SIZE(counter_event_type_name), event); +} + +static const char * const counter_component_type_name[] = { + "COUNTER_COMPONENT_NONE", + "COUNTER_COMPONENT_SIGNAL", + "COUNTER_COMPONENT_COUNT", + "COUNTER_COMPONENT_FUNCTION", + "COUNTER_COMPONENT_SYNAPSE_ACTION", + "COUNTER_COMPONENT_EXTENSION", +}; + +static int counter_arg_to_component_type(char *arg, __u8 *type) +{ + return find_match_or_number_from_array(arg, counter_component_type_name, + ARRAY_SIZE(counter_component_type_name), type); +} + +static const char * const counter_scope_name[] = { + "COUNTER_SCOPE_DEVICE", + "COUNTER_SCOPE_SIGNAL", + "COUNTER_SCOPE_COUNT", +}; + +static int counter_arg_to_scope(char *arg, __u8 *type) +{ + return find_match_or_number_from_array(arg, counter_scope_name, + ARRAY_SIZE(counter_scope_name), type); +} + +static void print_usage(void) +{ + fprintf(stderr, "Usage: counter_watch_events [options]...\n" + "Test various watch events for given counter device\n" + " --channel -c \n" + " Set watch.channel\n" + " --debug -d\n" + " Prints debug information\n" + " --event -e \n" + " Sets watch.event\n" + " --help -h\n" + " Prints usage\n" + " --device-num -n \n" + " Set device number (/dev/counter, default to 0)\n" + " --id -i \n" + " Set watch.component.id\n" + " --loop -l \n" + " Loop for a number of events (forever if n < 0)\n" + " --parent -p \n" + " Set watch.component.parent number\n" + " --scope -s \n" + " Set watch.component.scope\n" + " --type -t \n" + " Set watch.component.type\n" + "\n" + "Example with two watched events:\n\n" + "counter_watch_events -d \\\n" + "\t-t COUNTER_COMPONENT_COUNT -s COUNTER_SCOPE_COUNT" + " -e COUNTER_EVENT_OVERFLOW_UNDERFLOW -i 0 -c 0 \\\n" + "\t-t COUNTER_COMPONENT_EXTENSION -s COUNTER_SCOPE_COUNT" + " -e COUNTER_EVENT_CAPTURE -i 7 -c 3\n" + ); +} + +static void print_watch(struct counter_watch *watch, int nwatch) +{ + int i; + + /* prints the watch array in C-like structure */ + printf("watch[%d] = {\n", nwatch); + for (i = 0; i < nwatch; i++) { + printf(" [%d] =\t{\n" + "\t\t.component.type = %s\n" + "\t\t.component.scope = %s\n" + "\t\t.component.parent = %d\n" + "\t\t.component.id = %d\n" + "\t\t.event = %s\n" + "\t\t.channel = %d\n" + "\t},\n", + i, + counter_component_type_name[watch[i].component.type], + counter_scope_name[watch[i].component.scope], + watch[i].component.parent, + watch[i].component.id, + counter_event_type_name[watch[i].event], + watch[i].channel); + } + printf("};\n"); +} + +static const struct option longopts[] = { + { "channel", required_argument, 0, 'c' }, + { "debug", no_argument, 0, 'd' }, + { "event", required_argument, 0, 'e' }, + { "help", no_argument, 0, 'h' }, + { "device-num", required_argument, 0, 'n' }, + { "id", required_argument, 0, 'i' }, + { "loop", required_argument, 0, 'l' }, + { "parent", required_argument, 0, 'p' }, + { "scope", required_argument, 0, 's' }, + { "type", required_argument, 0, 't' }, + { }, +}; + +int main(int argc, char **argv) +{ + int c, fd, i, ret; + struct counter_event event_data; + char *device_name = NULL; + int debug = 0, loop = -1; + char *dummy; + int dev_num = 0, nwatch = 0, ncfg[] = {0, 0, 0, 0, 0, 0}; + int num_chan = 0, num_evt = 0, num_id = 0, num_p = 0, num_s = 0, num_t = 0; + struct counter_watch *watches; + + /* + * 1st pass: count events configurations number to allocate the watch array. + * Each watch argument can be repeated several times: each time it gets repeated, + * a corresponding watch is allocated (and configured) in 2nd pass. + */ + while ((c = getopt_long(argc, argv, "c:de:hn:i:l:p:s:t:", longopts, NULL)) != -1) { + switch (c) { + case 'c': + ncfg[0]++; + break; + case 'e': + ncfg[1]++; + break; + case 'i': + ncfg[2]++; + break; + case 'p': + ncfg[3]++; + break; + case 's': + ncfg[4]++; + break; + case 't': + ncfg[5]++; + break; + }; + }; + + for (i = 0; i < ARRAY_SIZE(ncfg); i++) + if (ncfg[i] > nwatch) + nwatch = ncfg[i]; + + if (nwatch) { + watches = calloc(nwatch, sizeof(*watches)); + } else { + /* default to simple watch example */ + watches = simple_watch; + nwatch = ARRAY_SIZE(simple_watch); + } + + /* 2nd pass: read arguments to fill in watch array */ + optind = 1; + while ((c = getopt_long(argc, argv, "c:de:hn:i:l:p:s:t:", longopts, NULL)) != -1) { + switch (c) { + case 'c': + /* watch.channel */ + watches[num_chan].channel = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + num_chan++; + break; + case 'd': + debug = 1; + break; + case 'e': + /* watch.event */ + ret = counter_arg_to_event_type(optarg, &watches[num_evt].event); + if (ret) + return ret; + num_evt++; + break; + case 'h': + print_usage(); + return -1; + case 'n': + errno = 0; + dev_num = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + break; + case 'i': + /* watch.component.id */ + watches[num_id].component.id = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + num_id++; + break; + case 'l': + loop = strtol(optarg, &dummy, 10); + if (errno) + return -errno; + break; + case 'p': + /* watch.component.parent */ + watches[num_p].component.parent = strtoul(optarg, &dummy, 10); + if (errno) + return -errno; + num_p++; + break; + case 's': + /* watch.component.scope */ + ret = counter_arg_to_scope(optarg, &watches[num_s].component.scope); + if (ret) + return ret; + num_s++; + break; + case 't': + /* watch.component.type */ + ret = counter_arg_to_component_type(optarg, &watches[num_t].component.type); + if (ret) + return ret; + num_t++; + break; + } + + }; + + if (debug) + print_watch(watches, nwatch); + + ret = asprintf(&device_name, "/dev/counter%d", dev_num); + if (ret < 0) + return -ENOMEM; + + if (debug) + printf("Opening %s\n", device_name); + + fd = open(device_name, O_RDWR); + if (fd == -1) { + perror("Unable to open counter device"); + return 1; + } + + for (i = 0; i < nwatch; i++) { + ret = ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + i); + if (ret == -1) { + fprintf(stderr, "Error adding watches[%d]: %s\n", i, + strerror(errno)); + return 1; + } + } + + ret = ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); + if (ret == -1) { + perror("Error enabling events"); + return 1; + } + + for (i = 0; loop <= 0 || i < loop; i++) { + ret = read(fd, &event_data, sizeof(event_data)); + if (ret == -1) { + perror("Failed to read event data"); + return 1; + } + + if (ret != sizeof(event_data)) { + fprintf(stderr, "Failed to read event data\n"); + return -EIO; + } + + printf("Timestamp: %llu\tData: %llu\t event: %s\tch: %d\n", + event_data.timestamp, event_data.value, + counter_event_type_name[event_data.watch.event], + event_data.watch.channel); + + if (event_data.status) { + fprintf(stderr, "Error %d: %s\n", event_data.status, + strerror(event_data.status)); + } + } + + return 0; +} From patchwork Tue Aug 29 13:40:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13368991 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 C1CBAC71153 for ; Tue, 29 Aug 2023 13:43:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229759AbjH2NnU (ORCPT ); Tue, 29 Aug 2023 09:43:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236844AbjH2NnG (ORCPT ); Tue, 29 Aug 2023 09:43:06 -0400 Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [185.132.182.106]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2CBFACEC; Tue, 29 Aug 2023 06:42:35 -0700 (PDT) Received: from pps.filterd (m0288072.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TBrQKU019514; Tue, 29 Aug 2023 15:40:58 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=PwB5UAXoCWyBxCXABWMO2FWSZwa0SK8ik9JE6Z0KgzY=; b=mR XwklBzu1lZv2pXDoprQzD52F3B1S7lXai4jSBGk9L/tSnxtmFJZrh5d1qToeUFzF JIKR68O5hK5O4y4E+nPz0VFdT9XyBBgM8rTwT7+ENWRAc6sfvJ4bNOHWVF7NjWiL Cro+J8Osro0ojOWAE8pYaFZ8V8yx6+tI0FisHi93g1Ms4g9XVL0loPcR/r2mIMBy HMK+7briU+7vs3GCUBTvITLA4HSssOhjeOlqjSshzuGd3SpYALtIWWCdKs5CTfHw B+NxPqxUaQn44cG3n+QxecZrzwp/HFbfs0TshkPAIB7gwaO8tZqxbvq5YGU+qsOD z5VXygz6RGA7blPf3EmA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq6tfmchm-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:40:58 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id AD7B910005E; Tue, 29 Aug 2023 15:40:57 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id A4DB82207DB; Tue, 29 Aug 2023 15:40:57 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:40:57 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 4/8] mfd: stm32-timers: add support for interrupts Date: Tue, 29 Aug 2023 15:40:25 +0200 Message-ID: <20230829134029.2402868-5-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org There are two types of STM32 timers that may have: - a global interrupt line - 4 dedicated interrupt lines. Those interrupts are optional as defined in the dt-bindings. Enforce checks on either one, four or no interrupts are provided with their names. Optionally get them here, to be used by child devices. Signed-off-by: Fabrice Gasnier --- drivers/mfd/stm32-timers.c | 46 ++++++++++++++++++++++++++++++++ include/linux/mfd/stm32-timers.h | 11 ++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/mfd/stm32-timers.c b/drivers/mfd/stm32-timers.c index 44ed2fce0319..51fb97bdab9c 100644 --- a/drivers/mfd/stm32-timers.c +++ b/drivers/mfd/stm32-timers.c @@ -214,6 +214,48 @@ static void stm32_timers_dma_remove(struct device *dev, dma_release_channel(ddata->dma.chans[i]); } +static const char * const stm32_timers_irq_name[STM32_TIMERS_MAX_IRQS] = { + "brk", "up", "trg-com", "cc" +}; + +static int stm32_timers_irq_probe(struct platform_device *pdev, + struct stm32_timers *ddata) +{ + int i, ret; + + /* + * STM32 Timer may have either: + * - a unique global interrupt line + * - four dedicated interrupt lines that may be handled separately. + * Optionally get them here, to be used by child devices. + */ + ret = platform_get_irq_byname_optional(pdev, "global"); + if (ret < 0 && ret != -ENXIO) { + return ret; + } else if (ret != -ENXIO) { + ddata->irq[STM32_TIMERS_IRQ_GLOBAL_BRK] = ret; + ddata->nr_irqs = 1; + return 0; + } + + for (i = 0; i < STM32_TIMERS_MAX_IRQS; i++) { + ret = platform_get_irq_byname_optional(pdev, stm32_timers_irq_name[i]); + if (ret < 0 && ret != -ENXIO) { + return ret; + } else if (ret != -ENXIO) { + ddata->irq[i] = ret; + ddata->nr_irqs++; + } + } + + if (ddata->nr_irqs && ddata->nr_irqs != STM32_TIMERS_MAX_IRQS) { + dev_err(&pdev->dev, "Invalid number of IRQs %d\n", ddata->nr_irqs); + return -EINVAL; + } + + return 0; +} + static int stm32_timers_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -245,6 +287,10 @@ static int stm32_timers_probe(struct platform_device *pdev) stm32_timers_get_arr_size(ddata); + ret = stm32_timers_irq_probe(pdev, ddata); + if (ret) + return ret; + ret = stm32_timers_dma_probe(dev, ddata); if (ret) { stm32_timers_dma_remove(dev, ddata); diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index 1b94325febb3..ca35af30745f 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -102,6 +102,15 @@ enum stm32_timers_dmas { STM32_TIMERS_MAX_DMAS, }; +/* STM32 Timer may have either a unique global interrupt or 4 interrupt lines */ +enum stm32_timers_irqs { + STM32_TIMERS_IRQ_GLOBAL_BRK, /* global or brk IRQ */ + STM32_TIMERS_IRQ_UP, + STM32_TIMERS_IRQ_TRG_COM, + STM32_TIMERS_IRQ_CC, + STM32_TIMERS_MAX_IRQS, +}; + /** * struct stm32_timers_dma - STM32 timer DMA handling. * @completion: end of DMA transfer completion @@ -123,6 +132,8 @@ struct stm32_timers { struct regmap *regmap; u32 max_arr; struct stm32_timers_dma dma; /* Only to be used by the parent */ + unsigned int nr_irqs; + int irq[STM32_TIMERS_MAX_IRQS]; }; #if IS_REACHABLE(CONFIG_MFD_STM32_TIMERS) From patchwork Tue Aug 29 13:40:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13368992 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 6B5D6C83F12 for ; Tue, 29 Aug 2023 13:45:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232425AbjH2Np0 (ORCPT ); Tue, 29 Aug 2023 09:45:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59002 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236447AbjH2NpK (ORCPT ); Tue, 29 Aug 2023 09:45:10 -0400 Received: from mx07-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 85587184; Tue, 29 Aug 2023 06:44:44 -0700 (PDT) Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 37TBpWh2021538; Tue, 29 Aug 2023 15:42:09 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=bQrDBJhz22wpFweWdN5Xj8vqxciJAWGqjrhNj1tNtrQ=; b=12 ehP/gUQjzfActRqLephKlJnWCk4/6NuQH/DHxglQfHv0UUx9SZhD6KI76wKpQVru wdnpneo930fw5EMgusIjqR0ow4Oy0Nq0vb3sgHC089Oejk7N94zVVmHtHHTF2dNc LeTegJ/lEbOld5XrxTjP0uP5NvpPOl3eaB+hji6IAX0YiDaUho4SV+lnHZgyDnzp 3832q0mvOTi+X5mrTLfbaoJ/DcC9Y/Li8JCBSC0koS/CrmfDmN9BUK8ZNrrbR8zx t6nONIXUBEed+0d2bgh8LB++fDeRL40NKijRVhb722KEZz/2LZMhZWMCYuaWSJpn KovtgL/v5+aqWpqU01oA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq6h44p6w-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:42:09 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 174D6100057; Tue, 29 Aug 2023 15:42:09 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 1179B22AFFD; Tue, 29 Aug 2023 15:42:09 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:42:08 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 5/8] counter: stm32-timer-cnt: rename quadrature signal Date: Tue, 29 Aug 2023 15:40:26 +0200 Message-ID: <20230829134029.2402868-6-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Rename "Channel 1 Quadrature B", as it corresponds to timer input ch2. I suspect it referred to the (unique) counter earlier, but the physical input really is CH2. Signed-off-by: Fabrice Gasnier --- drivers/counter/stm32-timer-cnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index 6206d2dc3d47..eae851f6db2c 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -283,7 +283,7 @@ static struct counter_signal stm32_signals[] = { }, { .id = 1, - .name = "Channel 1 Quadrature B" + .name = "Channel 2 Quadrature B" } }; From patchwork Tue Aug 29 13:40:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369082 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 7727FC6FA8F for ; Tue, 29 Aug 2023 14:30:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236759AbjH2OaI (ORCPT ); Tue, 29 Aug 2023 10:30:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53210 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236776AbjH2O35 (ORCPT ); Tue, 29 Aug 2023 10:29:57 -0400 Received: from mx08-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 298F3CC; Tue, 29 Aug 2023 07:29:53 -0700 (PDT) Received: from pps.filterd (m0369457.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TC1taC012172; Tue, 29 Aug 2023 15:42:10 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=BOqZ2SyfNpjhUHOPbQ6ZP82OTT/+YcIGQszooI+OKnk=; b=HB hoEjWxS0W31OIt1aLskq2Qml/g1DKnpxjeoRJ4jqO9LsOS2Gk0rHRedARizHMmfN r4QAvJo7/5vtpV1wTpUuWJXviWsDo6vS+cKpmv9cHuXwEPRqfLkmnTugCaizeyjm tST0bw6+8ttIz3i+cJxcozfmoYMNojoshKNnzUiDOzQn0tbOMf30Me34Z0v1g22v hKWkFQMPSSGuNME+4V90PxDe0hv6FFwjE5uoo2DVzfs2HzRuHu7oIdPxOml1Jkff MtIdTaYJ1bI7Jn5ogzA55hqBG1HfMfwnOIJ7ysQZ8CLWrLyWsyfNvFSSRkeUCzkr YFoOkNTVZFi1XeZcSN4A== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sqvbha31n-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:42:09 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 5201A10005E; Tue, 29 Aug 2023 15:42:09 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 4968722AFFD; Tue, 29 Aug 2023 15:42:09 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:42:08 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 6/8] counter: stm32-timer-cnt: introduce clock signal Date: Tue, 29 Aug 2023 15:40:27 +0200 Message-ID: <20230829134029.2402868-7-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Introduce the internal clock signal, used to count when in simple rising function. Define signal ids, to improve readability. Also add the "frequency" attribute for the clock signal, and "prescaler" for the counter. Whit this patch, signal action reports consistent state when "increase" function is used, and the counting frequency: $ echo increase > function $ grep -H "" signal*_action signal0_action:rising edge signal1_action:none signal2_action:none $ echo 1 > enable $ cat count 25425 $ cat count 44439 $ cat ../signal0/frequency 208877930 Signed-off-by: Fabrice Gasnier --- drivers/counter/stm32-timer-cnt.c | 84 ++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index eae851f6db2c..b8d201383a64 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -21,6 +21,10 @@ #define TIM_CCER_MASK (TIM_CCER_CC1P | TIM_CCER_CC1NP | \ TIM_CCER_CC2P | TIM_CCER_CC2NP) +#define STM32_CLOCK_SIG 0 +#define STM32_CH1_SIG 1 +#define STM32_CH2_SIG 2 + struct stm32_timer_regs { u32 cr1; u32 cnt; @@ -216,11 +220,44 @@ static int stm32_count_enable_write(struct counter_device *counter, return 0; } +static int stm32_count_prescaler_read(struct counter_device *counter, + struct counter_count *count, u64 *prescaler) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 psc; + + regmap_read(priv->regmap, TIM_PSC, &psc); + + *prescaler = psc + 1; + + return 0; +} + +static int stm32_count_prescaler_write(struct counter_device *counter, + struct counter_count *count, u64 prescaler) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 psc; + + if (!prescaler || prescaler > MAX_TIM_PSC + 1) + return -ERANGE; + + psc = prescaler - 1; + + return regmap_write(priv->regmap, TIM_PSC, psc); +} + static struct counter_comp stm32_count_ext[] = { COUNTER_COMP_DIRECTION(stm32_count_direction_read), COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), COUNTER_COMP_CEILING(stm32_count_ceiling_read, stm32_count_ceiling_write), + COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, + stm32_count_prescaler_write), +}; + +static const enum counter_synapse_action stm32_clock_synapse_actions[] = { + COUNTER_SYNAPSE_ACTION_RISING_EDGE, }; static const enum counter_synapse_action stm32_synapse_actions[] = { @@ -243,25 +280,31 @@ static int stm32_action_read(struct counter_device *counter, switch (function) { case COUNTER_FUNCTION_INCREASE: /* counts on internal clock when CEN=1 */ - *action = COUNTER_SYNAPSE_ACTION_NONE; + if (synapse->signal->id == STM32_CLOCK_SIG) + *action = COUNTER_SYNAPSE_ACTION_RISING_EDGE; + else + *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; case COUNTER_FUNCTION_QUADRATURE_X2_A: /* counts up/down on TI1FP1 edge depending on TI2FP2 level */ - if (synapse->signal->id == count->synapses[0].signal->id) + if (synapse->signal->id == STM32_CH1_SIG) *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; else *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; case COUNTER_FUNCTION_QUADRATURE_X2_B: /* counts up/down on TI2FP2 edge depending on TI1FP1 level */ - if (synapse->signal->id == count->synapses[1].signal->id) + if (synapse->signal->id == STM32_CH2_SIG) *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; else *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; case COUNTER_FUNCTION_QUADRATURE_X4: /* counts up/down on both TI1FP1 and TI2FP2 edges */ - *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + if (synapse->signal->id == STM32_CH1_SIG || synapse->signal->id == STM32_CH2_SIG) + *action = COUNTER_SYNAPSE_ACTION_BOTH_EDGES; + else + *action = COUNTER_SYNAPSE_ACTION_NONE; return 0; default: return -EINVAL; @@ -276,27 +319,52 @@ static const struct counter_ops stm32_timer_cnt_ops = { .action_read = stm32_action_read, }; +static int stm32_count_clk_get_freq(struct counter_device *counter, + struct counter_signal *signal, u64 *freq) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + *freq = clk_get_rate(priv->clk); + + return 0; +} + +static struct counter_comp stm32_count_clock_ext[] = { + COUNTER_COMP_SIGNAL_U64("frequency", stm32_count_clk_get_freq, NULL), +}; + static struct counter_signal stm32_signals[] = { { - .id = 0, + .id = STM32_CLOCK_SIG, + .name = "Clock Signal", + .ext = stm32_count_clock_ext, + .num_ext = ARRAY_SIZE(stm32_count_clock_ext), + }, + { + .id = STM32_CH1_SIG, .name = "Channel 1 Quadrature A" }, { - .id = 1, + .id = STM32_CH2_SIG, .name = "Channel 2 Quadrature B" } }; static struct counter_synapse stm32_count_synapses[] = { + { + .actions_list = stm32_clock_synapse_actions, + .num_actions = ARRAY_SIZE(stm32_clock_synapse_actions), + .signal = &stm32_signals[STM32_CLOCK_SIG] + }, { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[0] + .signal = &stm32_signals[STM32_CH1_SIG] }, { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[1] + .signal = &stm32_signals[STM32_CH2_SIG] } }; From patchwork Tue Aug 29 13:40:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369051 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 48C7EC83F18 for ; Tue, 29 Aug 2023 14:13:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232906AbjH2ONR (ORCPT ); Tue, 29 Aug 2023 10:13:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:52622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236884AbjH2OMw (ORCPT ); Tue, 29 Aug 2023 10:12:52 -0400 Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [185.132.182.106]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6301F198; Tue, 29 Aug 2023 07:12:48 -0700 (PDT) Received: from pps.filterd (m0288072.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TC171o019260; Tue, 29 Aug 2023 15:42:13 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=1/YJjDc86AStGiGgFDEynLvW3Our/eJ9zwFxAMjl428=; b=oV HWHaXee56Wa7RkhvYGclauCFFT5kagkZOKVAY18knexiWMPJ8JDUA0xM8BwJReS8 8JhwdhSZuYk2nEQb5RUSyDNfmk4bqGXwDgHH+L54P8KrXFa0gNp2jQUulaB69xkF Q+Gtxd7MRSX2toPupo0QCcuokHcdm+J0iHBofp27Hlz3L+dWknPxSSMS4gfOb8n2 KBTPBrMc2k8aQYK6PzFKV2E5dL52qwRCNPR6/+0E3+d8Gn5HGyY6ICVHXaElXPst jf9kiee2T93pTycOkkxGvCc30Z319sexCeZqc2yzCuOGT3A6LjVU99qXKwxp5op6 LfJHCA+2hAmZrrQfXxcQ== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq6tfmcp7-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:42:13 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 9A306100057; Tue, 29 Aug 2023 15:42:12 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 9146022AFFD; Tue, 29 Aug 2023 15:42:12 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:42:09 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 7/8] counter: stm32-timer-cnt: populate capture channels and check encoder Date: Tue, 29 Aug 2023 15:40:28 +0200 Message-ID: <20230829134029.2402868-8-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org This is a precursor patch to support capture channels on all possible channels and stm32 timer types. Original driver was intended to be used only as quadrature encoder and simple counter on internal clock. So, add ch3 and ch4 definition. Also add a check on encoder capability, so the driver may be probed for timer instances without encoder feature. This way, all timers may be used as simple counter on internal clock, starting from here. Encoder capability is retrieved by using the timer index (originally in stm32-timer-trigger driver and dt-bindings). The need to keep backward compatibility with existing device tree lead to parse aside trigger node. Add diversity as STM32 timers with capture feature may have either 4, 2, 1 or no cc (capture/compare) channels. Signed-off-by: Fabrice Gasnier --- drivers/counter/stm32-timer-cnt.c | 242 ++++++++++++++++++++++++++++-- 1 file changed, 231 insertions(+), 11 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index b8d201383a64..e39b3964bc9d 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #define STM32_CLOCK_SIG 0 #define STM32_CH1_SIG 1 #define STM32_CH2_SIG 2 +#define STM32_CH3_SIG 3 +#define STM32_CH4_SIG 4 struct stm32_timer_regs { u32 cr1; @@ -38,6 +41,9 @@ struct stm32_timer_cnt { u32 max_arr; bool enabled; struct stm32_timer_regs bak; + bool has_encoder; + u32 idx; + unsigned int nchannels; }; static const enum counter_function stm32_count_functions[] = { @@ -265,6 +271,10 @@ static const enum counter_synapse_action stm32_synapse_actions[] = { COUNTER_SYNAPSE_ACTION_BOTH_EDGES }; +static const enum counter_synapse_action stm32_synapse_ch_actions[] = { + COUNTER_SYNAPSE_ACTION_NONE, +}; + static int stm32_action_read(struct counter_device *counter, struct counter_count *count, struct counter_synapse *synapse, @@ -333,7 +343,8 @@ static struct counter_comp stm32_count_clock_ext[] = { COUNTER_COMP_SIGNAL_U64("frequency", stm32_count_clk_get_freq, NULL), }; -static struct counter_signal stm32_signals[] = { +/* STM32 Timer with quadrature encoder and 4 capture channels */ +static struct counter_signal stm32_signals_enc_4ch[] = { { .id = STM32_CLOCK_SIG, .name = "Clock Signal", @@ -347,38 +358,210 @@ static struct counter_signal stm32_signals[] = { { .id = STM32_CH2_SIG, .name = "Channel 2 Quadrature B" + }, + { + .id = STM32_CH3_SIG, + .name = "Channel 3" + }, + { + .id = STM32_CH4_SIG, + .name = "Channel 4" } }; -static struct counter_synapse stm32_count_synapses[] = { +static struct counter_synapse stm32_count_synapses_enc_4ch[] = { { .actions_list = stm32_clock_synapse_actions, .num_actions = ARRAY_SIZE(stm32_clock_synapse_actions), - .signal = &stm32_signals[STM32_CLOCK_SIG] + .signal = &stm32_signals_enc_4ch[STM32_CLOCK_SIG] }, { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[STM32_CH1_SIG] + .signal = &stm32_signals_enc_4ch[STM32_CH1_SIG] }, { .actions_list = stm32_synapse_actions, .num_actions = ARRAY_SIZE(stm32_synapse_actions), - .signal = &stm32_signals[STM32_CH2_SIG] + .signal = &stm32_signals_enc_4ch[STM32_CH2_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH3_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH4_SIG] + }, +}; + +static struct counter_count stm32_counts_enc_4ch = { + .id = 0, + .name = "Channel 1 Count", + .functions_list = stm32_count_functions, + .num_functions = ARRAY_SIZE(stm32_count_functions), + .synapses = stm32_count_synapses_enc_4ch, + .num_synapses = ARRAY_SIZE(stm32_count_synapses_enc_4ch), + .ext = stm32_count_ext, + .num_ext = ARRAY_SIZE(stm32_count_ext) +}; + +/* STM32 Timer with up to 4 capture channels (without encoder) */ +static struct counter_signal stm32_signals_4ch[] = { + { + .id = STM32_CLOCK_SIG, + .name = "Clock Signal", + .ext = stm32_count_clock_ext, + .num_ext = ARRAY_SIZE(stm32_count_clock_ext), + }, + { + .id = STM32_CH1_SIG, + .name = "Channel 1" + }, + { + .id = STM32_CH2_SIG, + .name = "Channel 2" + }, + { + .id = STM32_CH3_SIG, + .name = "Channel 3" + }, + { + .id = STM32_CH4_SIG, + .name = "Channel 4" } }; +static struct counter_synapse stm32_count_synapses_no_enc[] = { + { + .actions_list = stm32_clock_synapse_actions, + .num_actions = ARRAY_SIZE(stm32_clock_synapse_actions), + .signal = &stm32_signals_enc_4ch[STM32_CLOCK_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH1_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH2_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH3_SIG] + }, + { + .actions_list = stm32_synapse_ch_actions, + .num_actions = ARRAY_SIZE(stm32_synapse_ch_actions), + .signal = &stm32_signals_enc_4ch[STM32_CH4_SIG] + }, +}; + +static struct counter_count stm32_counts_4ch = { + .id = 0, + .name = "Channel 1 Count", + .functions_list = stm32_count_functions, + .num_functions = 1, /* increase */ + .synapses = stm32_count_synapses_no_enc, + .num_synapses = ARRAY_SIZE(stm32_count_synapses_no_enc), + .ext = stm32_count_ext, + .num_ext = ARRAY_SIZE(stm32_count_ext) +}; + +static struct counter_count stm32_counts_2ch = { + .id = 0, + .name = "Channel 1 Count", + .functions_list = stm32_count_functions, + .num_functions = 1, /* increase */ + .synapses = stm32_count_synapses_no_enc, + .num_synapses = 3, /* clock, ch1 and ch2 */ + .ext = stm32_count_ext, + .num_ext = ARRAY_SIZE(stm32_count_ext) +}; + +static struct counter_count stm32_counts_1ch = { + .id = 0, + .name = "Channel 1 Count", + .functions_list = stm32_count_functions, + .num_functions = 1, /* increase */ + .synapses = stm32_count_synapses_no_enc, + .num_synapses = 2, /* clock, ch1 */ + .ext = stm32_count_ext, + .num_ext = ARRAY_SIZE(stm32_count_ext) +}; + static struct counter_count stm32_counts = { .id = 0, .name = "Channel 1 Count", .functions_list = stm32_count_functions, - .num_functions = ARRAY_SIZE(stm32_count_functions), - .synapses = stm32_count_synapses, - .num_synapses = ARRAY_SIZE(stm32_count_synapses), + .num_functions = 1, /* increase */ + .synapses = stm32_count_synapses_no_enc, + .num_synapses = 1, /* clock only */ .ext = stm32_count_ext, .num_ext = ARRAY_SIZE(stm32_count_ext) }; +static void stm32_timer_cnt_detect_channels(struct platform_device *pdev, + struct stm32_timer_cnt *priv) +{ + u32 ccer, ccer_backup; + + regmap_read(priv->regmap, TIM_CCER, &ccer_backup); + regmap_set_bits(priv->regmap, TIM_CCER, TIM_CCER_CCXE); + regmap_read(priv->regmap, TIM_CCER, &ccer); + regmap_write(priv->regmap, TIM_CCER, ccer_backup); + priv->nchannels = hweight32(ccer & TIM_CCER_CCXE); + + dev_dbg(&pdev->dev, "has %d cc channels\n", priv->nchannels); +} + +/* encoder supported on TIM1 TIM2 TIM3 TIM4 TIM5 TIM8 */ +#define STM32_TIM_ENCODER_SUPPORTED (BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(7)) + +static const char * const stm32_timer_trigger_compat[] = { + "st,stm32-timer-trigger", + "st,stm32h7-timer-trigger", +}; + +static int stm32_timer_cnt_probe_encoder(struct platform_device *pdev, + struct stm32_timer_cnt *priv) +{ + struct device *parent = pdev->dev.parent; + struct device_node *tnode = NULL, *pnode = parent->of_node; + int i, ret; + + /* + * Need to retrieve the trigger node index from DT, to be able + * to determine if the counter supports encoder mode. It also + * enforce backward compatibility, and allow to support other + * counter modes in this driver (when the timer doesn't support + * encoder). + */ + for (i = 0; i < ARRAY_SIZE(stm32_timer_trigger_compat) && !tnode; i++) + tnode = of_get_compatible_child(pnode, stm32_timer_trigger_compat[i]); + if (!tnode) { + dev_err(&pdev->dev, "Can't find trigger node\n"); + return -ENODATA; + } + + ret = of_property_read_u32(tnode, "reg", &priv->idx); + if (ret) { + dev_err(&pdev->dev, "Can't get index (%d)\n", ret); + return ret; + } + + priv->has_encoder = !!(STM32_TIM_ENCODER_SUPPORTED & BIT(priv->idx)); + + dev_dbg(&pdev->dev, "encoder support: %s\n", priv->has_encoder ? "yes" : "no"); + + return 0; +} + static int stm32_timer_cnt_probe(struct platform_device *pdev) { struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent); @@ -400,13 +583,50 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; + ret = stm32_timer_cnt_probe_encoder(pdev, priv); + if (ret) + return ret; + + stm32_timer_cnt_detect_channels(pdev, priv); + counter->name = dev_name(dev); counter->parent = dev; counter->ops = &stm32_timer_cnt_ops; - counter->counts = &stm32_counts; counter->num_counts = 1; - counter->signals = stm32_signals; - counter->num_signals = ARRAY_SIZE(stm32_signals); + + /* + * Handle diversity for stm32 timers features. For now encoder is found with + * advanced timers or gp timers with 4 channels. Timers with less channels + * doesn't support encoder. + */ + switch (priv->nchannels) { + case 4: + if (priv->has_encoder) { + counter->counts = &stm32_counts_enc_4ch; + counter->signals = stm32_signals_enc_4ch; + counter->num_signals = ARRAY_SIZE(stm32_signals_enc_4ch); + } else { + counter->counts = &stm32_counts_4ch; + counter->signals = stm32_signals_4ch; + counter->num_signals = ARRAY_SIZE(stm32_signals_4ch); + } + break; + case 2: + counter->counts = &stm32_counts_2ch; + counter->signals = stm32_signals_4ch; + counter->num_signals = 3; /* clock, ch1 and ch2 */ + break; + case 1: + counter->counts = &stm32_counts_1ch; + counter->signals = stm32_signals_4ch; + counter->num_signals = 2; /* clock, ch1 */ + break; + default: + counter->counts = &stm32_counts; + counter->signals = stm32_signals_4ch; + counter->num_signals = 1; /* clock */ + break; + } platform_set_drvdata(pdev, priv); From patchwork Tue Aug 29 13:40:29 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fabrice Gasnier X-Patchwork-Id: 13369081 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 AB846C71153 for ; Tue, 29 Aug 2023 14:30:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229650AbjH2O3c (ORCPT ); Tue, 29 Aug 2023 10:29:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:50078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236697AbjH2O3a (ORCPT ); Tue, 29 Aug 2023 10:29:30 -0400 Received: from mx07-00178001.pphosted.com (mx07-00178001.pphosted.com [185.132.182.106]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8E3CCE1; Tue, 29 Aug 2023 07:29:26 -0700 (PDT) Received: from pps.filterd (m0241204.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.17.1.22/8.17.1.22) with ESMTP id 37TC4ipW022673; Tue, 29 Aug 2023 15:42:11 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h= from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding:content-type; s= selector1; bh=2b/Urmpixky2eQRaU/4lkgH9werd2cvqOZ7IIz+15Kg=; b=B3 yEacZ23+RBmGNw38HUdvSOMBJ3+psuaC/Qh9TPURsDgFZizoobV58QA4QKBhPrff 64q7FuI0Uey4zprLc0F63+lIHr9Rs5S2XdyR0xuQbTKdzIsg9tr03DyrqzlA5ite Whdmy8XuRzyZsDYgHiTswBtKKwMfncfIlXcxNf4iHlTOaRvs3D3ldm9fIi9optkA tHUT+NQ2b2gMppnNWxGct+9jkvezYGckpsuzfX92iBPMdtMp+m5wEhsxzWW2/Vkh Vex6uJtA4/FiVHXT0dppbfZSNMWinmIIz2E5zvjByvB4heqTBD23pej+wisbqIUj V0xMQ0V6f66IwFuhHI7g== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3sq8qwc3q4-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Tue, 29 Aug 2023 15:42:11 +0200 (MEST) Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 45AA2100057; Tue, 29 Aug 2023 15:42:11 +0200 (CEST) Received: from Webmail-eu.st.com (shfdag1node2.st.com [10.75.129.70]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 3CFE922AFFD; Tue, 29 Aug 2023 15:42:11 +0200 (CEST) Received: from localhost (10.201.22.39) by SHFDAG1NODE2.st.com (10.75.129.70) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2507.21; Tue, 29 Aug 2023 15:42:10 +0200 From: Fabrice Gasnier To: , CC: , , , , , Subject: [PATCH 8/8] counter: stm32-timer-cnt: add support for events Date: Tue, 29 Aug 2023 15:40:29 +0200 Message-ID: <20230829134029.2402868-9-fabrice.gasnier@foss.st.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> References: <20230829134029.2402868-1-fabrice.gasnier@foss.st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.22.39] X-ClientProxiedBy: EQNCAS1NODE3.st.com (10.75.129.80) To SHFDAG1NODE2.st.com (10.75.129.70) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.267,Aquarius:18.0.957,Hydra:6.0.601,FMLib:17.11.176.26 definitions=2023-08-29_10,2023-08-29_01,2023-05-22_02 Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org Add support for capture and overflow events. Also add the related validation and configuration. Captured counter value can be retrieved through CCRx register. Register and enable interrupts to push events. Signed-off-by: Fabrice Gasnier Acked-by: Lee Jones --- drivers/counter/stm32-timer-cnt.c | 279 +++++++++++++++++++++++++++++- include/linux/mfd/stm32-timers.h | 15 ++ 2 files changed, 285 insertions(+), 9 deletions(-) diff --git a/drivers/counter/stm32-timer-cnt.c b/drivers/counter/stm32-timer-cnt.c index e39b3964bc9d..05188f1da0b0 100644 --- a/drivers/counter/stm32-timer-cnt.c +++ b/drivers/counter/stm32-timer-cnt.c @@ -8,6 +8,7 @@ * */ #include +#include #include #include #include @@ -37,6 +38,7 @@ struct stm32_timer_regs { struct stm32_timer_cnt { struct regmap *regmap; + atomic_t nb_ovf; struct clk *clk; u32 max_arr; bool enabled; @@ -44,6 +46,8 @@ struct stm32_timer_cnt { bool has_encoder; u32 idx; unsigned int nchannels; + unsigned int nr_irqs; + u32 *irq; }; static const enum counter_function stm32_count_functions[] = { @@ -253,6 +257,60 @@ static int stm32_count_prescaler_write(struct counter_device *counter, return regmap_write(priv->regmap, TIM_PSC, psc); } +static int stm32_count_cap_read(struct counter_device *counter, + struct counter_count *count, + size_t ch, u64 *cap) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 ccrx; + + switch (ch) { + case 0: + regmap_read(priv->regmap, TIM_CCR1, &ccrx); + break; + case 1: + regmap_read(priv->regmap, TIM_CCR2, &ccrx); + break; + case 2: + regmap_read(priv->regmap, TIM_CCR3, &ccrx); + break; + case 3: + regmap_read(priv->regmap, TIM_CCR4, &ccrx); + break; + default: + return -EINVAL; + } + + dev_dbg(counter->parent, "CCR%zu: 0x%08x\n", ch, ccrx); + + *cap = ccrx; + + return 0; +} + +static int stm32_count_nb_ovf_read(struct counter_device *counter, + struct counter_count *count, u64 *val) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + *val = atomic_read(&priv->nb_ovf); + + return 0; +} + +static int stm32_count_nb_ovf_write(struct counter_device *counter, + struct counter_count *count, u64 val) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + if (val > U32_MAX) + return -ERANGE; + + atomic_set(&priv->nb_ovf, val); + + return 0; +} + static struct counter_comp stm32_count_ext[] = { COUNTER_COMP_DIRECTION(stm32_count_direction_read), COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), @@ -260,6 +318,43 @@ static struct counter_comp stm32_count_ext[] = { stm32_count_ceiling_write), COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, stm32_count_prescaler_write), + COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), +}; + +static DEFINE_COUNTER_ARRAY_CAPTURE(stm32_count_cap_array_4ch, 4); +static struct counter_comp stm32_count_4ch_ext[] = { + COUNTER_COMP_DIRECTION(stm32_count_direction_read), + COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), + COUNTER_COMP_CEILING(stm32_count_ceiling_read, + stm32_count_ceiling_write), + COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, + stm32_count_prescaler_write), + COUNTER_COMP_ARRAY_CAPTURE(stm32_count_cap_read, NULL, stm32_count_cap_array_4ch), + COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), +}; + +static DEFINE_COUNTER_ARRAY_CAPTURE(stm32_count_cap_array_2ch, 2); +static struct counter_comp stm32_count_2ch_ext[] = { + COUNTER_COMP_DIRECTION(stm32_count_direction_read), + COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), + COUNTER_COMP_CEILING(stm32_count_ceiling_read, + stm32_count_ceiling_write), + COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, + stm32_count_prescaler_write), + COUNTER_COMP_ARRAY_CAPTURE(stm32_count_cap_read, NULL, stm32_count_cap_array_2ch), + COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), +}; + +static DEFINE_COUNTER_ARRAY_CAPTURE(stm32_count_cap_array_1ch, 1); +static struct counter_comp stm32_count_1ch_ext[] = { + COUNTER_COMP_DIRECTION(stm32_count_direction_read), + COUNTER_COMP_ENABLE(stm32_count_enable_read, stm32_count_enable_write), + COUNTER_COMP_CEILING(stm32_count_ceiling_read, + stm32_count_ceiling_write), + COUNTER_COMP_COUNT_U64("prescaler", stm32_count_prescaler_read, + stm32_count_prescaler_write), + COUNTER_COMP_ARRAY_CAPTURE(stm32_count_cap_read, NULL, stm32_count_cap_array_1ch), + COUNTER_COMP_COUNT_U64("num_overflows", stm32_count_nb_ovf_read, stm32_count_nb_ovf_write), }; static const enum counter_synapse_action stm32_clock_synapse_actions[] = { @@ -321,12 +416,130 @@ static int stm32_action_read(struct counter_device *counter, } } +struct stm32_count_cc_regs { + u32 ccmr_reg; + u32 ccmr_mask; + u32 ccmr_bits; + u32 ccer_bits; +}; + +static const struct stm32_count_cc_regs stm32_cc[] = { + { TIM_CCMR1, TIM_CCMR_CC1S, TIM_CCMR_CC1S_TI1, + TIM_CCER_CC1E | TIM_CCER_CC1P | TIM_CCER_CC1NP }, + { TIM_CCMR1, TIM_CCMR_CC2S, TIM_CCMR_CC2S_TI2, + TIM_CCER_CC2E | TIM_CCER_CC2P | TIM_CCER_CC2NP }, + { TIM_CCMR2, TIM_CCMR_CC3S, TIM_CCMR_CC3S_TI3, + TIM_CCER_CC3E | TIM_CCER_CC3P | TIM_CCER_CC3NP }, + { TIM_CCMR2, TIM_CCMR_CC4S, TIM_CCMR_CC4S_TI4, + TIM_CCER_CC4E | TIM_CCER_CC4P | TIM_CCER_CC4NP }, +}; + +static int stm32_count_capture_configure(struct counter_device *counter, unsigned int ch, + bool enable) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 ccmr, ccer, sr; + + if (ch >= ARRAY_SIZE(stm32_cc)) { + dev_err(counter->parent, "invalid ch: %d\n", ch); + return -EINVAL; + } + + /* + * configure channel in input capture mode, map channel 1 on TI1, channel2 on TI2... + * Select both edges / non-inverted to trigger a capture. + */ + if (enable) { + /* first clear possibly latched capture flag upon enabling */ + regmap_read(priv->regmap, TIM_CCER, &ccer); + if (!(ccer & stm32_cc[ch].ccer_bits)) { + sr = ~TIM_SR_CC_IF(ch); + regmap_write(priv->regmap, TIM_SR, sr); + } + regmap_update_bits(priv->regmap, stm32_cc[ch].ccmr_reg, stm32_cc[ch].ccmr_mask, + stm32_cc[ch].ccmr_bits); + regmap_set_bits(priv->regmap, TIM_CCER, stm32_cc[ch].ccer_bits); + } else { + regmap_clear_bits(priv->regmap, TIM_CCER, stm32_cc[ch].ccer_bits); + regmap_clear_bits(priv->regmap, stm32_cc[ch].ccmr_reg, stm32_cc[ch].ccmr_mask); + } + + regmap_read(priv->regmap, stm32_cc[ch].ccmr_reg, &ccmr); + regmap_read(priv->regmap, TIM_CCER, &ccer); + dev_dbg(counter->parent, "%s(%s) ch%d 0x%08x 0x%08x\n", __func__, enable ? "ena" : "dis", + ch, ccmr, ccer); + + return 0; +} + +static int stm32_count_events_configure(struct counter_device *counter) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + struct counter_event_node *event_node; + int i, ret; + u32 val, dier = 0; + + list_for_each_entry(event_node, &counter->events_list, l) { + switch (event_node->event) { + case COUNTER_EVENT_OVERFLOW_UNDERFLOW: + /* first clear possibly latched UIF before enabling */ + regmap_read(priv->regmap, TIM_DIER, &val); + if (!(val & TIM_DIER_UIE)) + regmap_write(priv->regmap, TIM_SR, (u32)~TIM_SR_UIF); + dier |= TIM_DIER_UIE; + break; + case COUNTER_EVENT_CAPTURE: + ret = stm32_count_capture_configure(counter, event_node->channel, true); + if (ret) + return ret; + dier |= TIM_DIER_CC_IE(event_node->channel); + break; + default: + /* should never reach this path */ + return -EINVAL; + } + } + + regmap_write(priv->regmap, TIM_DIER, dier); + + /* check for disabled capture events */ + for (i = 0 ; i < priv->nchannels; i++) { + if (!(dier & TIM_DIER_CC_IE(i))) { + ret = stm32_count_capture_configure(counter, i, false); + if (ret) + return ret; + } + } + + return 0; +} + +static int stm32_count_watch_validate(struct counter_device *counter, + const struct counter_watch *watch) +{ + struct stm32_timer_cnt *const priv = counter_priv(counter); + + switch (watch->event) { + case COUNTER_EVENT_CAPTURE: + if (watch->channel >= priv->nchannels) { + dev_err(counter->parent, "Invalid channel %d\n", watch->channel); + return -EINVAL; + } + case COUNTER_EVENT_OVERFLOW_UNDERFLOW: + return 0; + default: + return -EINVAL; + } +} + static const struct counter_ops stm32_timer_cnt_ops = { .count_read = stm32_count_read, .count_write = stm32_count_write, .function_read = stm32_count_function_read, .function_write = stm32_count_function_write, .action_read = stm32_action_read, + .events_configure = stm32_count_events_configure, + .watch_validate = stm32_count_watch_validate, }; static int stm32_count_clk_get_freq(struct counter_device *counter, @@ -404,8 +617,8 @@ static struct counter_count stm32_counts_enc_4ch = { .num_functions = ARRAY_SIZE(stm32_count_functions), .synapses = stm32_count_synapses_enc_4ch, .num_synapses = ARRAY_SIZE(stm32_count_synapses_enc_4ch), - .ext = stm32_count_ext, - .num_ext = ARRAY_SIZE(stm32_count_ext) + .ext = stm32_count_4ch_ext, + .num_ext = ARRAY_SIZE(stm32_count_4ch_ext) }; /* STM32 Timer with up to 4 capture channels (without encoder) */ @@ -469,8 +682,8 @@ static struct counter_count stm32_counts_4ch = { .num_functions = 1, /* increase */ .synapses = stm32_count_synapses_no_enc, .num_synapses = ARRAY_SIZE(stm32_count_synapses_no_enc), - .ext = stm32_count_ext, - .num_ext = ARRAY_SIZE(stm32_count_ext) + .ext = stm32_count_4ch_ext, + .num_ext = ARRAY_SIZE(stm32_count_4ch_ext) }; static struct counter_count stm32_counts_2ch = { @@ -480,8 +693,8 @@ static struct counter_count stm32_counts_2ch = { .num_functions = 1, /* increase */ .synapses = stm32_count_synapses_no_enc, .num_synapses = 3, /* clock, ch1 and ch2 */ - .ext = stm32_count_ext, - .num_ext = ARRAY_SIZE(stm32_count_ext) + .ext = stm32_count_2ch_ext, + .num_ext = ARRAY_SIZE(stm32_count_2ch_ext) }; static struct counter_count stm32_counts_1ch = { @@ -491,8 +704,8 @@ static struct counter_count stm32_counts_1ch = { .num_functions = 1, /* increase */ .synapses = stm32_count_synapses_no_enc, .num_synapses = 2, /* clock, ch1 */ - .ext = stm32_count_ext, - .num_ext = ARRAY_SIZE(stm32_count_ext) + .ext = stm32_count_1ch_ext, + .num_ext = ARRAY_SIZE(stm32_count_1ch_ext) }; static struct counter_count stm32_counts = { @@ -506,6 +719,42 @@ static struct counter_count stm32_counts = { .num_ext = ARRAY_SIZE(stm32_count_ext) }; +static irqreturn_t stm32_timer_cnt_isr(int irq, void *ptr) +{ + struct counter_device *counter = ptr; + struct stm32_timer_cnt *const priv = counter_priv(counter); + u32 clr = GENMASK(31, 0); /* SR flags can be cleared by writing 0 (wr 1 has no effect) */ + u32 sr, dier; + int i; + + regmap_read(priv->regmap, TIM_SR, &sr); + regmap_read(priv->regmap, TIM_DIER, &dier); + /* Only take care of enabled IRQs */ + dier &= (TIM_DIER_UIE | TIM_DIER_CC1IE | TIM_DIER_CC2IE | TIM_DIER_CC3IE | TIM_DIER_CC4IE); + sr &= dier; + + if (sr & TIM_SR_UIF) { + atomic_inc(&priv->nb_ovf); + counter_push_event(counter, COUNTER_EVENT_OVERFLOW_UNDERFLOW, 0); + dev_dbg(counter->parent, "COUNTER_EVENT_OVERFLOW_UNDERFLOW\n"); + /* SR flags can be cleared by writing 0, only clear relevant flag */ + clr &= ~TIM_SR_UIF; + } + + /* Check capture events */ + for (i = 0 ; i < priv->nchannels; i++) { + if (sr & TIM_SR_CC_IF(i)) { + counter_push_event(counter, COUNTER_EVENT_CAPTURE, i); + clr &= ~TIM_SR_CC_IF(i); + dev_dbg(counter->parent, "COUNTER_EVENT_CAPTURE, %d\n", i); + } + } + + regmap_write(priv->regmap, TIM_SR, clr); + + return IRQ_HANDLED; +}; + static void stm32_timer_cnt_detect_channels(struct platform_device *pdev, struct stm32_timer_cnt *priv) { @@ -568,7 +817,7 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct stm32_timer_cnt *priv; struct counter_device *counter; - int ret; + int i, ret; if (IS_ERR_OR_NULL(ddata)) return -EINVAL; @@ -582,6 +831,8 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) priv->regmap = ddata->regmap; priv->clk = ddata->clk; priv->max_arr = ddata->max_arr; + priv->nr_irqs = ddata->nr_irqs; + priv->irq = ddata->irq; ret = stm32_timer_cnt_probe_encoder(pdev, priv); if (ret) @@ -630,6 +881,16 @@ static int stm32_timer_cnt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); + for (i = 0; i < priv->nr_irqs; i++) { + ret = devm_request_irq(&pdev->dev, priv->irq[i], stm32_timer_cnt_isr, + 0, dev_name(dev), counter); + if (ret) { + dev_err(dev, "Failed to request irq %d (err %d)\n", + priv->irq[i], ret); + return ret; + } + } + /* Reset input selector to its default input */ regmap_write(priv->regmap, TIM_TISEL, 0x0); diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h index ca35af30745f..f0c6e6d2df66 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -41,6 +41,11 @@ #define TIM_SMCR_SMS (BIT(0) | BIT(1) | BIT(2)) /* Slave mode selection */ #define TIM_SMCR_TS (BIT(4) | BIT(5) | BIT(6)) /* Trigger selection */ #define TIM_DIER_UIE BIT(0) /* Update interrupt */ +#define TIM_DIER_CC1IE BIT(1) /* CC1 Interrupt Enable */ +#define TIM_DIER_CC2IE BIT(2) /* CC2 Interrupt Enable */ +#define TIM_DIER_CC3IE BIT(3) /* CC3 Interrupt Enable */ +#define TIM_DIER_CC4IE BIT(4) /* CC4 Interrupt Enable */ +#define TIM_DIER_CC_IE(x) BIT((x) + 1) /* CC1, CC2, CC3, CC4 interrupt enable */ #define TIM_DIER_UDE BIT(8) /* Update DMA request Enable */ #define TIM_DIER_CC1DE BIT(9) /* CC1 DMA request Enable */ #define TIM_DIER_CC2DE BIT(10) /* CC2 DMA request Enable */ @@ -49,6 +54,7 @@ #define TIM_DIER_COMDE BIT(13) /* COM DMA request Enable */ #define TIM_DIER_TDE BIT(14) /* Trigger DMA request Enable */ #define TIM_SR_UIF BIT(0) /* Update interrupt flag */ +#define TIM_SR_CC_IF(x) BIT((x) + 1) /* CC1, CC2, CC3, CC4 interrupt flag */ #define TIM_EGR_UG BIT(0) /* Update Generation */ #define TIM_CCMR_PE BIT(3) /* Channel Preload Enable */ #define TIM_CCMR_M1 (BIT(6) | BIT(5)) /* Channel PWM Mode 1 */ @@ -60,16 +66,23 @@ #define TIM_CCMR_CC1S_TI2 BIT(1) /* IC1/IC3 selects TI2/TI4 */ #define TIM_CCMR_CC2S_TI2 BIT(8) /* IC2/IC4 selects TI2/TI4 */ #define TIM_CCMR_CC2S_TI1 BIT(9) /* IC2/IC4 selects TI1/TI3 */ +#define TIM_CCMR_CC3S (BIT(0) | BIT(1)) /* Capture/compare 3 sel */ +#define TIM_CCMR_CC4S (BIT(8) | BIT(9)) /* Capture/compare 4 sel */ +#define TIM_CCMR_CC3S_TI3 BIT(0) /* IC3 selects TI3 */ +#define TIM_CCMR_CC4S_TI4 BIT(8) /* IC4 selects TI4 */ #define TIM_CCER_CC1E BIT(0) /* Capt/Comp 1 out Ena */ #define TIM_CCER_CC1P BIT(1) /* Capt/Comp 1 Polarity */ #define TIM_CCER_CC1NE BIT(2) /* Capt/Comp 1N out Ena */ #define TIM_CCER_CC1NP BIT(3) /* Capt/Comp 1N Polarity */ #define TIM_CCER_CC2E BIT(4) /* Capt/Comp 2 out Ena */ #define TIM_CCER_CC2P BIT(5) /* Capt/Comp 2 Polarity */ +#define TIM_CCER_CC2NP BIT(7) /* Capt/Comp 2N Polarity */ #define TIM_CCER_CC3E BIT(8) /* Capt/Comp 3 out Ena */ #define TIM_CCER_CC3P BIT(9) /* Capt/Comp 3 Polarity */ +#define TIM_CCER_CC3NP BIT(11) /* Capt/Comp 3N Polarity */ #define TIM_CCER_CC4E BIT(12) /* Capt/Comp 4 out Ena */ #define TIM_CCER_CC4P BIT(13) /* Capt/Comp 4 Polarity */ +#define TIM_CCER_CC4NP BIT(15) /* Capt/Comp 4N Polarity */ #define TIM_CCER_CCXE (BIT(0) | BIT(4) | BIT(8) | BIT(12)) #define TIM_BDTR_BKE(x) BIT(12 + (x) * 12) /* Break input enable */ #define TIM_BDTR_BKP(x) BIT(13 + (x) * 12) /* Break input polarity */ @@ -91,6 +104,8 @@ #define TIM_BDTR_BKF_MASK 0xF #define TIM_BDTR_BKF_SHIFT(x) (16 + (x) * 4) +#define MAX_TIM_IC_CHANNELS 4 /* Max number of input capature channels */ + enum stm32_timers_dmas { STM32_TIMERS_DMA_CH1, STM32_TIMERS_DMA_CH2,