From patchwork Mon Aug 6 22:29:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 10558019 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id A7B811390 for ; Mon, 6 Aug 2018 22:33:55 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 93FE7297BF for ; Mon, 6 Aug 2018 22:33:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 85F4E297CE; Mon, 6 Aug 2018 22:33:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,DKIM_VALID,FREEMAIL_FROM,MAILING_LIST_MULTI autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BC4B8297BF for ; Mon, 6 Aug 2018 22:33:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=JRF68eH5NYxwXFlVSfRVJwtKimLWvjEdEQd8Ewxg0iQ=; b=csqdmC8eF2odlK7OB3rt0ENzzm laMgSVfL7HCyYwj1QnMHz9I+C8BuSd4N74lKmrYqKCCopKqCH/SUZjL8IJ78VjKi9ozo5JIQcEfHE guUSn9Z4RImWfgIup3csBqEOvG3eDumt3YFNqjUXjwkB0MJgv5SSSNfs/eMYeNFRLjd4zjktnhaES 7wp6VLxdftaNueQn2ZUuh7EXCpVoGrZUZ0BhzrJWc+bxT87rr2lzOmGDaBdVk92BYX0/gPBoShaL1 GY9/BaJQVcDoqnkDFmkvI3vQrPgHhTQPqrl+olxCQZwPxxXPC8LtrHZ82XRZM4K4Qsv81R4XN6MPc pW1gVl6A==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmo4S-0003WY-20; Mon, 06 Aug 2018 22:33:48 +0000 Received: from mail-lf1-x141.google.com ([2a00:1450:4864:20::141]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1fmo0a-0005T1-G1; Mon, 06 Aug 2018 22:30:06 +0000 Received: by mail-lf1-x141.google.com with SMTP id j143-v6so10187991lfj.12; Mon, 06 Aug 2018 15:29:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ebIIlYMRwOV2gYgWi7T9qT+QmjkOUcUsHwsxQZ0n6Tk=; b=WhVqN1At68jh0Y7HUfCj4y3WSZTCj9P89b9nXlw1PQ5rNy/IL1jpTWuCmtpfoPOY5v FuKeruPHb2LFCCkefM4a38qkltc7Z/OxFQreVur2EJFzQaUmhKykhcSJkIKsS5x/5WAL gmq4YoM86EfL7xH591j4hLOipTrI3ZvQ7uQ5my67n/bnsejrZftrqBD+P3aGYztAOxPJ aN/ePJL8CCYoSGIfda/+uHePDu23bZwMp3O6qFC2NIVz7GyR/y2wnBVWQHJ3qF1WDPGx gu08VrnAtUogqQWJSFijFjwBFj4Qz5qAyxt5H+BiuGLQ9ZKEjkwbJUcK8Bh452DMCNI5 0w6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ebIIlYMRwOV2gYgWi7T9qT+QmjkOUcUsHwsxQZ0n6Tk=; b=s2uSGccCRiVAADvJNPDIoQIichH7MwIRtxvGuMK5gSoOsMJPfehGQFZHC7oYpoiQiG 49jPgB5vEyHb4plpYRgOX24hR215Nz3qly3clZCpU8ayNRooNnVgrePYll5OOCG9RSv6 6kgo+hg9mp5OAYRohneNw7Vmw+/ICQVAhgW4+Tyez9GQN92cS4X1I6gMHq1sAeBhwPMF v2zJkQHKJc50A8Wwnc52VI1ClUMsAdAf+DKL2AzmoUlG7ydQGSZFUDg9vZTxBWFKGkas dnt0Z7TAv7ITAFmdmtXyTdOa1djUSl227NlFmssOWxydNQZJM12Aw6IO/ThIGGQk1g/I qesA== X-Gm-Message-State: AOUpUlHGDikgjv6h41pWgk6WyIghWB3D3Q2oy5HbgNd8f72bUYzCWfHy RBYDKH/qI9XM49q+TXSzqJU= X-Google-Smtp-Source: AAOMgpdN9LZehLcDgBA7w0nORZ3SY79wH/6RfscsmGRAExgcZ4fMvUNIaZmKPIAqkV0EoWG/wHvlrw== X-Received: by 2002:a19:7609:: with SMTP id c9-v6mr11952619lff.73.1533594581791; Mon, 06 Aug 2018 15:29:41 -0700 (PDT) Received: from z50.lan (93-181-165-181.internetia.net.pl. [93.181.165.181]) by smtp.gmail.com with ESMTPSA id o4-v6sm2438561ljc.67.2018.08.06.15.29.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 06 Aug 2018 15:29:41 -0700 (PDT) From: Janusz Krzysztofik To: Boris Brezillon , Linus Walleij Subject: [RFC PATCH v2 10/12] gpiolib: Introduce bitmap get/set array API extension Date: Tue, 7 Aug 2018 00:29:16 +0200 Message-Id: <20180806222918.12644-11-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180806222918.12644-1-jmkrzyszt@gmail.com> References: <20180718235710.18242-1-jmkrzyszt@gmail.com> <20180806222918.12644-1-jmkrzyszt@gmail.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180806_152948_988996_1FB1A8D8 X-CRM114-Status: GOOD ( 17.77 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-omap@vger.kernel.org, Jonathan Corbet , Tony Lindgren , Richard Weinberger , linux-gpio@vger.kernel.org, Aaro Koskinen , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Marek Vasut , Janusz Krzysztofik , linux-mtd@lists.infradead.org, Miquel Raynal , Brian Norris , David Woodhouse , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Certain GPIO array lookups may return arrays marked as applicable for fast get/set array operations. In order to make use of that information, a new API extension which allows passing it to get/set functions is needed. Create a set of frontends to get/set array functions which accept strict descriptor array structures returned by gpiod_get_array() instead of arbitrary descriptor arrays. Since the intended purpose of the new API extension is to speed up get/set array operations, also replace array of integer values argument with their bitmap representation, ready for being passed directly to chip callback functions, without iterating them. Applicability of the new API is limited to arrays not exceeding bit length of type unsigned long (32 pins). Signed-off-by: Janusz Krzysztofik --- Documentation/driver-api/gpio/consumer.rst | 26 ++++ drivers/gpio/gpiolib.c | 209 +++++++++++++++++++++++++++++ include/linux/gpio/consumer.h | 14 ++ 3 files changed, 249 insertions(+) diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index 38a990b5f3b6..bec4eab3b87c 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -383,6 +383,32 @@ or negative on error. Note the difference to gpiod_get_value(), which returns 0 or 1 on success to convey the GPIO value. With the array functions, the GPIO values are stored in value_array rather than passed back as return value. +Additionally, the following variants of the above functions exist which operate +on bitmaps of values instead of arrays of values:: + + int gpiod_get_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits); + int gpiod_get_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits); + int gpiod_get_array_bitmap_cansleep(struct gpio_desc *desc_array, + unsigned long *bits); + int gpiod_get_raw_array_bitmap_cansleep(struct gpio_desc **desc_array, + unsigned long *bits) + + void gpiod_set_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits) + void gpiod_set_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bitmap) + void gpiod_set_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) + void gpiod_set_raw_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) + +Unlike their counterparts, these functions don't accept arbitrary GPIO +descriptor arrays, only those of type struct gpio_descs returned by +gpiod_get_array() and its variants. Supported array size is limited to the size +of the bitmap, i.e., sizeof(unsigned long). + GPIOs mapped to IRQs -------------------- diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c50bcec6e2d7..5b541364dee0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2836,6 +2836,27 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, return 0; } +int gpiod_get_array_bitmap_complex(bool raw, bool can_sleep, + struct gpio_descs *array, + unsigned long *bits) +{ + int value_array[sizeof(*bits)]; + int i; + + if (array->ndescs > sizeof(*bits)) + return -EINVAL; + + i = gpiod_get_array_value_complex(raw, can_sleep, array->ndescs, + array->desc, value_array); + if (i) + return i; + + for (i = 0; i < array->ndescs; i++) + __assign_bit(i, bits, value_array[i]); + + return 0; +} + /** * gpiod_get_raw_value() - return a gpio's raw value * @desc: gpio whose value will be returned @@ -2929,6 +2950,50 @@ int gpiod_get_array_value(unsigned int array_size, } EXPORT_SYMBOL_GPL(gpiod_get_array_value); +/** + * gpiod_get_raw_array_bitmap() - read raw values from an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be read, obtained + * with gpiod_get_array(), + * @bits: bitmap to store the read values + * + * Read the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. Return 0 in case of success, + * else an error code. + * + * This function should be called from contexts where we cannot sleep, + * and it will complain if the GPIO chip functions potentially sleep. + */ +int gpiod_get_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits) +{ + if (!desc_array) + return -EINVAL; + return gpiod_get_array_bitmap_complex(true, false, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_array_bitmap); + +/** + * gpiod_get_array_bitmap() - read values from an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be read, obtained + * with gpiod_get_array(), + * @bits: bitmap to store the read values + * + * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. Return 0 in case of success, else an error code. + * + * This function should be called from contexts where we cannot sleep, + * and it will complain if the GPIO chip functions potentially sleep. + */ + +int gpiod_get_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits) +{ + if (!desc_array) + return -EINVAL; + return gpiod_get_array_bitmap_complex(false, false, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_array_bitmap); + /* * gpio_set_open_drain_value_commit() - Set the open drain gpio's value. * @desc: gpio descriptor whose state need to be set. @@ -3081,6 +3146,23 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, return 0; } +int gpiod_set_array_bitmap_complex(bool raw, bool can_sleep, + struct gpio_descs *array, + unsigned long *bits) +{ + int value_array[sizeof(*bits)]; + int i; + + if (array->ndescs > sizeof(*bits)) + return -EINVAL; + + for (i = 0; i < array->ndescs; i++) + value_array[i] = test_bit(i, bits); + + return gpiod_set_array_value_complex(raw, can_sleep, array->ndescs, + array->desc, value_array); +} + /** * gpiod_set_raw_value() - assign a gpio's raw value * @desc: gpio whose value will be assigned @@ -3185,6 +3267,48 @@ void gpiod_set_array_value(unsigned int array_size, } EXPORT_SYMBOL_GPL(gpiod_set_array_value); +/** + * gpiod_set_raw_array_bitmap() - assign values to an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be assigned, + * obtained with gpiod_get_array(), + * @bits: bitmap of values to assign + * + * Set the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +int gpiod_set_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits) +{ + if (!desc_array) + return -EINVAL; + return gpiod_set_array_bitmap_complex(true, false, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_set_raw_array_bitmap); + +/** + * gpiod_set_array_bitmap() - assign values to an array of GPIOs + * @array_size: number of elements in the descriptor / value arrays + * @desc_array: array of GPIO descriptors whose values will be assigned + * @bits: bitmap of values to assign + * + * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. + * + * This function should be called from contexts where we cannot sleep, and will + * complain if the GPIO chip functions potentially sleep. + */ +void gpiod_set_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits) +{ + if (!desc_array) + return; + gpiod_set_array_bitmap_complex(false, false, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_set_array_bitmap); + /** * gpiod_cansleep() - report whether gpio value access may sleep * @desc: gpio to check @@ -3446,6 +3570,49 @@ int gpiod_get_array_value_cansleep(unsigned int array_size, } EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); +/** + * gpiod_get_raw_array_bitmap_cansleep() - read raw values from array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be read, obtained + * with gpiod_get_array(), + * @bits: bitmap to store the read values + * + * Read the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. Return 0 in case of success, + * else an error code. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_get_raw_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return -EINVAL; + return gpiod_get_array_bitmap_complex(true, true, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_get_raw_array_bitmap_cansleep); + +/** + * gpiod_get_array_bitmap_cansleep() - read values from an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be read, obtained + * with gpiod_get_array(), + * @bits: bitmap to store the read values + * + * Read the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. Return 0 in case of success, else an error code. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_get_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return -EINVAL; + return gpiod_get_array_bitmap_complex(false, true, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_get_array_bitmap_cansleep); + /** * gpiod_set_raw_value_cansleep() - assign a gpio's raw value * @desc: gpio whose value will be assigned @@ -3545,6 +3712,48 @@ void gpiod_set_array_value_cansleep(unsigned int array_size, } EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); +/** + * gpiod_set_raw_array_bitmap_cansleep() - assign values to an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be assigned, + * obtained with gpiod_get_array(), + * @bits: bitmap of values to assign + * + * Set the raw values of the GPIOs, i.e. the values of the physical lines + * without regard for their ACTIVE_LOW status. + * + * This function is to be called from contexts that can sleep. + */ +int gpiod_set_raw_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return -EINVAL; + return gpiod_set_array_bitmap_complex(true, true, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_set_raw_array_bitmap_cansleep); + +/** + * gpiod_set_array_bitmap_cansleep() - assign values to an array of GPIOs + * @desc_array: array of GPIO descriptors whose values will be assigned, + * obtained with gpiod_get_array(), + * @bits: bitmap of values to assign + * + * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status + * into account. + * + * This function is to be called from contexts that can sleep. + */ +void gpiod_set_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits) +{ + might_sleep_if(extra_checks); + if (!desc_array) + return; + gpiod_set_array_bitmap_complex(false, true, desc_array, bits); +} +EXPORT_SYMBOL_GPL(gpiod_set_array_bitmap_cansleep); + /** * gpiod_add_lookup_table() - register GPIO device consumers * @table: table of consumers to register diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 862ee027a02f..1eabce4fc6c5 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -106,35 +106,49 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value); int gpiod_get_value(const struct gpio_desc *desc); int gpiod_get_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_get_array_bitmap(struct gpio_descs *desc_array, unsigned long *bits); void gpiod_set_value(struct gpio_desc *desc, int value); void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +void gpiod_set_array_bitmap(struct gpio_descs *desc_array, unsigned long *bits); int gpiod_get_raw_value(const struct gpio_desc *desc); int gpiod_get_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_get_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits); void gpiod_set_raw_value(struct gpio_desc *desc, int value); int gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_set_raw_array_bitmap(struct gpio_descs *desc_array, + unsigned long *bits); /* Value get/set from sleeping context */ int gpiod_get_value_cansleep(const struct gpio_desc *desc); int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_get_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits); void gpiod_set_value_cansleep(struct gpio_desc *desc, int value); void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +void gpiod_set_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits); int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc); int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_get_raw_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits); void gpiod_set_raw_value_cansleep(struct gpio_desc *desc, int value); int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, int *value_array); +int gpiod_set_raw_array_bitmap_cansleep(struct gpio_descs *desc_array, + unsigned long *bits); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);