From patchwork Fri Aug 31 22:56:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 10584561 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 0E2A05A4 for ; Fri, 31 Aug 2018 22:55:51 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EF3112C1AE for ; Fri, 31 Aug 2018 22:55:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E031B2C6B9; Fri, 31 Aug 2018 22:55:50 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 9EA072C1AE for ; Fri, 31 Aug 2018 22:55:48 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727342AbeIADF0 (ORCPT ); Fri, 31 Aug 2018 23:05:26 -0400 Received: from mail-lf1-f65.google.com ([209.85.167.65]:42890 "EHLO mail-lf1-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727560AbeIADFZ (ORCPT ); Fri, 31 Aug 2018 23:05:25 -0400 Received: by mail-lf1-f65.google.com with SMTP id z11-v6so11145356lff.9; Fri, 31 Aug 2018 15:55:42 -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=KS/H/PZvPbG/OL4CiHMG7Q6sUiSUVZLfKpoyToC/WP8=; b=g30gsYh54rXNlIBYA+23fQEO30UMg5k4eotTjeQN2UbwXz7sJtU7zBhruelAJhbeS4 HlzPssDUUsV9rFYpaP+iRPnxUVd3SxyIf8hESDzEhtj3Kd8CNQ9+/d9CiyK6KhbtU/D7 xPvwI7htS3BCQXFY/qEs2TwsOt1sX500OmJVwNMpASyCMVf1Tx7p2mO4FZsjlb7AV/rq E3MlCLOI/VWVi/iMH8/yJlgqvHmx+OmUN0yJgeoa1mgIFA/H/luandpm041T31+dwe40 xvJ+qg62t27Sgj3areTGmmrwv+xcGZjD67+s3AxfSuAlaA0sV5Yf3ZnDHXiuAQ07DVL3 1yZQ== 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=KS/H/PZvPbG/OL4CiHMG7Q6sUiSUVZLfKpoyToC/WP8=; b=Zd4hz8iGcoFFfAwHwU8T+DVhE6I7t3LCn6jBGvUoffZMth1JBzwpwkXB+gSi10GUIM HMdQEFlFxMyp572jxoxfMuEmzggS7pNIIC3HKtS+DNHIP6h966c7E3yoIA5cGB91pJm1 qMC5tqT4FGPHjlwRqmC32rEuoR3KqP3OYXyqoc+273wyGbe4SS4yPMknrLrGUJNZCQxS y9f3GzKCoae8C8eUDgGsNE6INPAdk7gjTfUfJdi2rTRygeTv9luC1ee00N/MgXwNHENZ NJjgpCzPBkT1NE/WdK6mEqYEqHg31eavtjyPoyURJTURKxPU6hSFs7m5JK5MCWc7hsbd BA0A== X-Gm-Message-State: APzg51AUnC3CRtwagS//sVWwvOUGqv6ERIuVgmnsdCiiPIZZ28aWyEiG Cb/7/9O1T0FALE9V0OzcYGo= X-Google-Smtp-Source: ANB0Vdbcn2s/20AhE75MmldXY43M2Gp3XFUS055eS2b1WgZ1LLuzQkugp8qBZTwjOQ8NoD9clMhjLw== X-Received: by 2002:a19:e44c:: with SMTP id b73-v6mr2291004lfh.117.1535756141943; Fri, 31 Aug 2018 15:55:41 -0700 (PDT) Received: from localhost.localdomain (apn-37-248-212-140.dynamic.gprs.plus.pl. [37.248.212.140]) by smtp.gmail.com with ESMTPSA id v20-v6sm1969187ljc.94.2018.08.31.15.55.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 15:55:41 -0700 (PDT) From: Janusz Krzysztofik To: Linus Walleij Cc: Jonathan Corbet , Miguel Ojeda Sandonis , Peter Korsgaard , Peter Rosin , Ulf Hansson , Andrew Lunn , Florian Fainelli , "David S. Miller" , Dominik Brodowski , Greg Kroah-Hartman , Kishon Vijay Abraham I , Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , Hartmut Knaack , Peter Meerwald-Stadler , Jiri Slaby , Willy Tarreau , Geert Uytterhoeven , linux-doc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-mmc@vger.kernel.org, netdev@vger.kernel.org, linux-iio@vger.kernel.org, devel@driverdev.osuosl.org, linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Janusz Krzysztofik Subject: [PATCH v6 1/4] gpiolib: Pass bitmaps, not integer arrays, to get/set array Date: Sat, 1 Sep 2018 00:56:13 +0200 Message-Id: <20180831225616.29221-2-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180831225616.29221-1-jmkrzyszt@gmail.com> References: <20180829204900.19390-1-jmkrzyszt@gmail.com> <20180831225616.29221-1-jmkrzyszt@gmail.com> Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Most users of get/set array functions iterate consecutive bits of data, usually a single integer, while processing array of results obtained from, or building an array of values to be passed to those functions. Save time wasted on those iterations by changing the functions' API to accept bitmaps. All current users are updated as well. More benefits from the change are expected as soon as planned support for accepting/passing those bitmaps directly from/to respective GPIO chip callbacks if applicable is implemented. Cc: Jonathan Corbet Cc: Miguel Ojeda Sandonis Cc: Peter Korsgaard Cc: Peter Rosin Cc: Andrew Lunn Cc: Florian Fainelli Cc: "David S. Miller" Cc: Dominik Brodowski Cc: Kishon Vijay Abraham I Cc: Lars-Peter Clausen Cc: Michael Hennerich Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Peter Meerwald-Stadler Cc: Greg Kroah-Hartman Cc: Jiri Slaby Signed-off-by: Janusz Krzysztofik Acked-by: Ulf Hansson --- Documentation/driver-api/gpio/consumer.rst | 22 ++++---- drivers/auxdisplay/hd44780.c | 62 ++++++++------------- drivers/bus/ts-nbus.c | 21 ++----- drivers/gpio/gpio-max3191x.c | 17 +++--- drivers/gpio/gpiolib.c | 86 +++++++++++++++-------------- drivers/gpio/gpiolib.h | 4 +- drivers/i2c/muxes/i2c-mux-gpio.c | 14 ++--- drivers/mmc/core/pwrseq_simple.c | 13 ++--- drivers/mux/gpio.c | 15 ++--- drivers/net/phy/mdio-mux-gpio.c | 11 ++-- drivers/pcmcia/soc_common.c | 11 ++-- drivers/phy/motorola/phy-mapphone-mdm6600.c | 17 +++--- drivers/staging/iio/adc/ad7606.c | 9 +-- drivers/tty/serial/serial_mctrl_gpio.c | 7 ++- include/linux/gpio/consumer.h | 18 +++--- 15 files changed, 145 insertions(+), 182 deletions(-) diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index aa03f389d41d..ed68042ddccf 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -323,29 +323,29 @@ The following functions get or set the values of an array of GPIOs:: int gpiod_get_array_value(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); int gpiod_get_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) void gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) void gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) The array can be an arbitrary set of GPIOs. The functions will try to access GPIOs belonging to the same bank or chip simultaneously if supported by the @@ -356,8 +356,8 @@ accessed sequentially. The functions take three arguments: * array_size - the number of array elements * desc_array - an array of GPIO descriptors - * value_array - an array to store the GPIOs' values (get) or - an array of values to assign to the GPIOs (set) + * value_bitmap - a bitmap to store the GPIOs' values (get) or + a bitmap of values to assign to the GPIOs (set) The descriptor array can be obtained using the gpiod_get_array() function or one of its variants. If the group of descriptors returned by that function @@ -366,7 +366,7 @@ the struct gpio_descs returned by gpiod_get_array():: struct gpio_descs *my_gpio_descs = gpiod_get_array(...); gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc, - my_gpio_values); + my_gpio_value_bitmap); It is also possible to access a completely arbitrary array of descriptors. The descriptors may be obtained using any combination of gpiod_get() and diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index f1a42f0f1ded..7ee4f9a65bfc 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -62,20 +62,15 @@ static void hd44780_strobe_gpio(struct hd44780 *hd) /* write to an LCD panel register in 8 bit GPIO mode */ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) { - int values[10]; /* for DATA[0-7], RS, RW */ - unsigned int i, n; - - for (i = 0; i < 8; i++) - values[PIN_DATA0 + i] = !!(val & BIT(i)); - values[PIN_CTRL_RS] = rs; - n = 9; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + DECLARE_BITMAP(value_bitmap, 10); /* for DATA[0-7], RS, RW */ + unsigned int n; + + *value_bitmap = val; + __assign_bit(8, value_bitmap, rs); + n = hd->pins[PIN_CTRL_RW] ? 10 : 9; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], values); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], value_bitmap); hd44780_strobe_gpio(hd); } @@ -83,32 +78,25 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) /* write to an LCD panel register in 4 bit GPIO mode */ static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) { - int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ - unsigned int i, n; + DECLARE_BITMAP(value_bitmap, 6); /* for DATA[4-7], RS, RW */ + unsigned int n; /* High nibble + RS, RW */ - for (i = 4; i < 8; i++) - values[PIN_DATA0 + i] = !!(val & BIT(i)); - values[PIN_CTRL_RS] = rs; - n = 5; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + *value_bitmap = val >> 4; + __assign_bit(4, value_bitmap, rs); + n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); hd44780_strobe_gpio(hd); /* Low nibble */ - for (i = 0; i < 4; i++) - values[PIN_DATA4 + i] = !!(val & BIT(i)); + *value_bitmap &= ~0x0f; + *value_bitmap |= val & 0x0f; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); hd44780_strobe_gpio(hd); } @@ -155,23 +143,17 @@ static void hd44780_write_cmd_gpio4(struct charlcd *lcd, int cmd) /* Send 4-bits of a command to the LCD panel in raw 4 bit GPIO mode */ static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) { - int values[10]; /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ + /* for DATA[0-7], RS, RW, but DATA[0-3] is unused */ + DECLARE_BITMAP(value_bitmap, 6); struct hd44780 *hd = lcd->drvdata; - unsigned int i, n; + unsigned int n; /* Command nibble + RS, RW */ - for (i = 0; i < 4; i++) - values[PIN_DATA4 + i] = !!(cmd & BIT(i)); - values[PIN_CTRL_RS] = 0; - n = 5; - if (hd->pins[PIN_CTRL_RW]) { - values[PIN_CTRL_RW] = 0; - n++; - } + *value_bitmap = cmd & 0x0f; + n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], - &values[PIN_DATA4]); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); hd44780_strobe_gpio(hd); } diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 073fd9011154..2ac5239df865 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -110,13 +110,11 @@ static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction) */ static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus) { - int i; - int values[8]; - - for (i = 0; i < 8; i++) - values[i] = 0; + DECLARE_BITMAP(value_bitmap, 8); + + *value_bitmap = 0; - gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, values); + gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, value_bitmap); gpiod_set_value_cansleep(ts_nbus->csn, 0); gpiod_set_value_cansleep(ts_nbus->strobe, 0); gpiod_set_value_cansleep(ts_nbus->ale, 0); @@ -157,16 +155,9 @@ static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val) static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte) { struct gpio_descs *gpios = ts_nbus->data; - int i; - int values[8]; - - for (i = 0; i < 8; i++) - if (byte & BIT(i)) - values[i] = 1; - else - values[i] = 0; + DECLARE_BITMAP(value_bitmap, 8) = { byte, }; - gpiod_set_array_value_cansleep(8, gpios->desc, values); + gpiod_set_array_value_cansleep(8, gpios->desc, value_bitmap); } /* diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index b5b9cb1fda50..c4ec1c82af27 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -315,17 +315,20 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, struct gpio_desc **desc, int value) { - int i, *values; + unsigned long *value_bitmap; - values = kmalloc_array(ndescs, sizeof(*values), GFP_KERNEL); - if (!values) + value_bitmap = kmalloc_array(BITS_TO_LONGS(ndescs), + sizeof(*value_bitmap), GFP_KERNEL); + if (!value_bitmap) return; - for (i = 0; i < ndescs; i++) - values[i] = value; + if (value) + bitmap_fill(value_bitmap, ndescs); + else + bitmap_zero(value_bitmap, ndescs); - gpiod_set_array_value_cansleep(ndescs, desc, values); - kfree(values); + gpiod_set_array_value_cansleep(ndescs, desc, value_bitmap); + kfree(value_bitmap); } static struct gpio_descs *devm_gpiod_get_array_optional_count( diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e8f8a1999393..f0e9ffa8cab6 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -427,7 +427,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, struct linehandle_state *lh = filep->private_data; void __user *ip = (void __user *)arg; struct gpiohandle_data ghd; - int vals[GPIOHANDLES_MAX]; + unsigned long value_bitmap[BITS_TO_LONGS(GPIOHANDLES_MAX)]; int i; if (cmd == GPIOHANDLE_GET_LINE_VALUES_IOCTL) { @@ -436,13 +436,13 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, true, lh->numdescs, lh->descs, - vals); + value_bitmap); if (ret) return ret; memset(&ghd, 0, sizeof(ghd)); for (i = 0; i < lh->numdescs; i++) - ghd.values[i] = vals[i]; + ghd.values[i] = test_bit(i, value_bitmap); if (copy_to_user(ip, &ghd, sizeof(ghd))) return -EFAULT; @@ -461,14 +461,14 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, /* Clamp all values to [0,1] */ for (i = 0; i < lh->numdescs; i++) - vals[i] = !!ghd.values[i]; + __assign_bit(i, value_bitmap, !!ghd.values[i]); /* Reuse the array setting function */ return gpiod_set_array_value_complex(false, true, lh->numdescs, lh->descs, - vals); + value_bitmap); } return -EINVAL; } @@ -2784,7 +2784,7 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip, int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { int i = 0; @@ -2835,7 +2835,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; - value_array[j] = value; + __assign_bit(j, value_bitmap, value); trace_gpio_value(desc_to_gpio(desc), 1, value); } @@ -2895,9 +2895,9 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); /** * gpiod_get_raw_array_value() - read raw values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @value_bitmap: 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, @@ -2907,20 +2907,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_raw_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, false, array_size, - desc_array, value_array); + desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); /** * gpiod_get_array_value() - read values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @value_bitnap: 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. @@ -2929,12 +2930,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); * and it will complain if the GPIO chip functions potentially sleep. */ int gpiod_get_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, false, array_size, - desc_array, value_array); + desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value); @@ -3027,7 +3029,7 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { int i = 0; @@ -3056,7 +3058,7 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, do { struct gpio_desc *desc = desc_array[i]; int hwgpio = gpio_chip_hwgpio(desc); - int value = value_array[i]; + int value = test_bit(i, value_bitmap); if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; @@ -3152,9 +3154,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); /** * gpiod_set_raw_array_value() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @value_bitmap: 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. @@ -3163,20 +3165,21 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); * complain if the GPIO chip functions potentially sleep. */ int gpiod_set_raw_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, false, array_size, - desc_array, value_array); + desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); /** * gpiod_set_array_value() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @value_bitmap: bitmap of values to assign * * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. @@ -3185,12 +3188,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); * complain if the GPIO chip functions potentially sleep. */ void gpiod_set_array_value(unsigned int array_size, - struct gpio_desc **desc_array, int *value_array) + struct gpio_desc **desc_array, + unsigned long *value_bitmap) { if (!desc_array) return; gpiod_set_array_value_complex(false, false, array_size, desc_array, - value_array); + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value); @@ -3410,9 +3414,9 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); /** * gpiod_get_raw_array_value_cansleep() - read raw values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @value_bitmap: 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, @@ -3422,21 +3426,21 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); */ int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, true, array_size, - desc_array, value_array); + desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); /** * gpiod_get_array_value_cansleep() - read values from an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be read - * @value_array: array to store the read values + * @value_bitmap: 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. @@ -3445,13 +3449,13 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); */ int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, true, array_size, - desc_array, value_array); + desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); @@ -3493,9 +3497,9 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** * gpiod_set_raw_array_value_cansleep() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @value_bitmap: 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. @@ -3504,13 +3508,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); */ int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, true, array_size, desc_array, - value_array); + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); @@ -3533,9 +3537,9 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) /** * gpiod_set_array_value_cansleep() - assign values to an array of GPIOs - * @array_size: number of elements in the descriptor / value arrays + * @array_size: number of elements in the descriptor array / value bitmap * @desc_array: array of GPIO descriptors whose values will be assigned - * @value_array: array of values to assign + * @value_bitmap: bitmap of values to assign * * Set the logical values of the GPIOs, i.e. taking their ACTIVE_LOW status * into account. @@ -3544,13 +3548,13 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) */ void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, - int *value_array) + unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return; gpiod_set_array_value_complex(false, true, array_size, desc_array, - value_array); + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index a7e49fef73d4..11e83d2eef89 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -187,11 +187,11 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, - int *value_array); + unsigned long *value_bitmap); /* This is just passed between gpiolib and devres */ struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 401308e3d036..e28ddc20000d 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -22,18 +22,16 @@ struct gpiomux { struct i2c_mux_gpio_platform_data data; unsigned gpio_base; struct gpio_desc **gpios; - int *values; }; static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) { - int i; - - for (i = 0; i < mux->data.n_gpios; i++) - mux->values[i] = (val >> i) & 1; + DECLARE_BITMAP(value_bitmap, mux->data.n_gpios); + + *value_bitmap = val; gpiod_set_array_value_cansleep(mux->data.n_gpios, - mux->gpios, mux->values); + mux->gpios, value_bitmap); } static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) @@ -182,15 +180,13 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - mux->data.n_gpios * sizeof(*mux->gpios) + - mux->data.n_gpios * sizeof(*mux->values), 0, + mux->data.n_gpios * sizeof(*mux->gpios), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; goto alloc_failed; } mux->gpios = muxc->priv; - mux->values = (int *)(mux->gpios + mux->data.n_gpios); muxc->priv = mux; platform_set_drvdata(pdev, muxc); diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index a8b9fee4d62a..fd7791e072b3 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -40,18 +40,13 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, struct gpio_descs *reset_gpios = pwrseq->reset_gpios; if (!IS_ERR(reset_gpios)) { - int i, *values; int nvalues = reset_gpios->ndescs; + DECLARE_BITMAP(value_bitmap, nvalues); - values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL); - if (!values) - return; + *value_bitmap = value; - for (i = 0; i < nvalues; i++) - values[i] = value; - - gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values); - kfree(values); + gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, + value_bitmap); } } diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 6fdd9316db8b..17b7b1c21d90 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -17,20 +17,17 @@ struct mux_gpio { struct gpio_descs *gpios; - int *val; }; static int mux_gpio_set(struct mux_control *mux, int state) { struct mux_gpio *mux_gpio = mux_chip_priv(mux->chip); - int i; - - for (i = 0; i < mux_gpio->gpios->ndescs; i++) - mux_gpio->val[i] = (state >> i) & 1; + DECLARE_BITMAP(value_bitmap, mux_gpio->gpios->ndescs); + + *value_bitmap = state; gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, - mux_gpio->gpios->desc, - mux_gpio->val); + mux_gpio->gpios->desc, value_bitmap); return 0; } @@ -58,13 +55,11 @@ static int mux_gpio_probe(struct platform_device *pdev) if (pins < 0) return pins; - mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio) + - pins * sizeof(*mux_gpio->val)); + mux_chip = devm_mux_chip_alloc(dev, 1, sizeof(*mux_gpio)); if (IS_ERR(mux_chip)) return PTR_ERR(mux_chip); mux_gpio = mux_chip_priv(mux_chip); - mux_gpio->val = (int *)(mux_gpio + 1); mux_chip->ops = &mux_gpio_ops; mux_gpio->gpios = devm_gpiod_get_array(dev, "mux", GPIOD_OUT_LOW); diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index bc90764a8b8d..3907e9528949 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -20,23 +20,21 @@ struct mdio_mux_gpio_state { struct gpio_descs *gpios; void *mux_handle; - int values[]; }; static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, void *data) { struct mdio_mux_gpio_state *s = data; - unsigned int n; + DECLARE_BITMAP(value_bitmap, s->gpios->ndescs); if (current_child == desired_child) return 0; - for (n = 0; n < s->gpios->ndescs; n++) - s->values[n] = (desired_child >> n) & 1; + *value_bitmap = desired_child; gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc, - s->values); + value_bitmap); return 0; } @@ -51,8 +49,7 @@ static int mdio_mux_gpio_probe(struct platform_device *pdev) if (IS_ERR(gpios)) return PTR_ERR(gpios); - s = devm_kzalloc(&pdev->dev, struct_size(s, values, gpios->ndescs), - GFP_KERNEL); + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); if (!s) { gpiod_put_array(gpios); return -ENOMEM; diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index c5f2344c189b..44288b1a57ee 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -351,19 +351,22 @@ static int soc_common_pcmcia_config_skt( if (ret == 0) { struct gpio_desc *descs[2]; - int values[2], n = 0; + DECLARE_BITMAP(value_bitmap, 2); + int n = 0; if (skt->gpio_reset) { descs[n] = skt->gpio_reset; - values[n++] = !!(state->flags & SS_RESET); + __assign_bit(n++, value_bitmap, + !!(state->flags & SS_RESET)); } if (skt->gpio_bus_enable) { descs[n] = skt->gpio_bus_enable; - values[n++] = !!(state->flags & SS_OUTPUT_ENA); + __assign_bit(n++, value_bitmap, + !!(state->flags & SS_OUTPUT_ENA)); } if (n) - gpiod_set_array_value_cansleep(n, descs, values); + gpiod_set_array_value_cansleep(n, descs, value_bitmap); /* * This really needs a better solution. The IRQ diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index 0075fb0bef8c..b348272f7f1a 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -157,15 +157,12 @@ static const struct phy_ops gpio_usb_ops = { */ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) { - int values[PHY_MDM6600_NR_CMD_LINES]; - int i; + DECLARE_BITMAP(value_bitmap, PHY_MDM6600_NR_CMD_LINES); - val &= (1 << PHY_MDM6600_NR_CMD_LINES) - 1; - for (i = 0; i < PHY_MDM6600_NR_CMD_LINES; i++) - values[i] = (val & BIT(i)) >> i; + *value_bitmap = val & ((1 << PHY_MDM6600_NR_CMD_LINES) - 1); gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES, - ddata->cmd_gpios->desc, values); + ddata->cmd_gpios->desc, value_bitmap); } /** @@ -176,7 +173,7 @@ static void phy_mdm6600_status(struct work_struct *work) { struct phy_mdm6600 *ddata; struct device *dev; - int values[PHY_MDM6600_NR_STATUS_LINES]; + DECLARE_BITMAP(value_bitmap, PHY_MDM6600_NR_STATUS_LINES); int error, i, val = 0; ddata = container_of(work, struct phy_mdm6600, status_work.work); @@ -184,14 +181,14 @@ static void phy_mdm6600_status(struct work_struct *work) error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES, ddata->status_gpios->desc, - values); + value_bitmap); if (error) return; for (i = 0; i < PHY_MDM6600_NR_STATUS_LINES; i++) { - val |= values[i] << i; + val |= test_bit(i, value_bitmap) << i; dev_dbg(ddata->dev, "XXX %s: i: %i values[i]: %i val: %i\n", - __func__, i, values[i], val); + __func__, i, test_bit(i, value_bitmap), val); } ddata->status = val; diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 25b9fcd5e3a4..18b6d10b0176 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -202,7 +202,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, long mask) { struct ad7606_state *st = iio_priv(indio_dev); - int values[3]; + DECLARE_BITMAP(value_bitmap, 3); int ret, i; switch (mask) { @@ -227,13 +227,10 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, if (ret < 0) return ret; - values[0] = (ret >> 0) & 1; - values[1] = (ret >> 1) & 1; - values[2] = (ret >> 2) & 1; + *value_bitmap = ret; mutex_lock(&st->lock); - gpiod_set_array_value(ARRAY_SIZE(values), st->gpio_os->desc, - values); + gpiod_set_array_value(3, st->gpio_os->desc, value_bitmap); st->oversampling = val; mutex_unlock(&st->lock); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index 1c06325beaca..edfe8c688479 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -40,7 +40,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) { enum mctrl_gpio_idx i; struct gpio_desc *desc_array[UART_GPIO_MAX]; - int value_array[UART_GPIO_MAX]; + DECLARE_BITMAP(value_bitmap, UART_GPIO_MAX); unsigned int count = 0; if (gpios == NULL) @@ -49,10 +49,11 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) for (i = 0; i < UART_GPIO_MAX; i++) if (gpios->gpio[i] && mctrl_gpios_desc[i].dir_out) { desc_array[count] = gpios->gpio[i]; - value_array[count] = !!(mctrl & mctrl_gpios_desc[i].mctrl); + __assign_bit(count, value_bitmap, + !!(mctrl & mctrl_gpios_desc[i].mctrl)); count++; } - gpiod_set_array_value(count, desc_array, value_array); + gpiod_set_array_value(count, desc_array, value_bitmap); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 21ddbe440030..1b21dc7b0fad 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -104,36 +104,38 @@ int gpiod_direction_output_raw(struct gpio_desc *desc, int value); /* Value get/set from non-sleeping context */ 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); + struct gpio_desc **desc_array, + unsigned long *value_bitmap); 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); + struct gpio_desc **desc_array, + unsigned long *value_bitmap); 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); + unsigned long *value_bitmap); 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); + unsigned long *value_bitmap); /* 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); + unsigned long *value_bitmap); 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); + unsigned long *value_bitmap); 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); + unsigned long *value_bitmap); 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); + unsigned long *value_bitmap); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); int gpiod_set_transitory(struct gpio_desc *desc, bool transitory); From patchwork Fri Aug 31 22:56:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 10584567 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 C99935A4 for ; Fri, 31 Aug 2018 22:56:05 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id BC3912C1AE for ; Fri, 31 Aug 2018 22:56:05 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id AFE082C6B9; Fri, 31 Aug 2018 22:56:05 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2E5262C1AE for ; Fri, 31 Aug 2018 22:56:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727774AbeIADFf (ORCPT ); Fri, 31 Aug 2018 23:05:35 -0400 Received: from mail-lj1-f195.google.com ([209.85.208.195]:39365 "EHLO mail-lj1-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727637AbeIADFf (ORCPT ); Fri, 31 Aug 2018 23:05:35 -0400 Received: by mail-lj1-f195.google.com with SMTP id l15-v6so11254840lji.6; Fri, 31 Aug 2018 15:55:53 -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=Ss6DAMy39ntUSy+xns54ZkDEt4V3I8DvbWAXkdjX6Cw=; b=I5vmFWKay/8fsuwJkkKhQknOmVgPjapOICdS8P8FjP9IpBYLN9P2rNIumlBR6IWTpP DZYczlWEuoyG+4SMSal67H9CkfulX7VtQ0DDzXZnTQQa/fWh5AI0yUUQ7yJYAuKcR8WX CgpVWK61J4A11L8wrKh+M3kVTW0r2h2RKlRpKFNZj0fJmaRCz1WBQTxrXKS8AIHUyVEo 1s95gh1bH7GhJHLsMBgLigpZcA1cpwVmRQR3MOH1McUYJbA406qNuvKIpiBUzIe2/Hw9 bbVZ4Okl7ONt/CkYbUJZgnjVfa/o5Zc3o27kGnK+1lemAroAUOK3QfwDPatiMvmFkIrr Wi7Q== 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=Ss6DAMy39ntUSy+xns54ZkDEt4V3I8DvbWAXkdjX6Cw=; b=PVxiP1yyucIMQNtp6boZQ3MLm8MlSkwxjiM7NuDs1aNV0sy2xt/CLdBsHnUSKn2dXk XIzDmrssSHGA4f2GTv1YthWCBGf6v5+XUGfKD28EOFI0gT4x3tIFxY1TYS8g7D1ICqSC FXLkgElKwtORPyuaAM6JIg5flwEvr7/QhKiDoNOPAZMaHMHIRuFwdE2uLmqOfO9nKrtD cp0uLSc2qPpwjBSmCg/jHXjKinMruBoT6xOv0DXnVb3tWe6aPGKqsl1cGn/Buh+88EkS 2X7SmlChLLi5B4QgDFQkTcH16NzbaPEPMT03HKhIhYlWL2areQeGCg1nQZsH0zR98RDQ On0w== X-Gm-Message-State: APzg51A0MRJPlFQ+xJTeQXErI6E4UNvsjLM6AmYudXMI5l5NvLvS/07o dhDOnq1TmuN8TDjmX0zogkA= X-Google-Smtp-Source: ANB0VdZJROPOizorcDsvK+v+g/NpLKuS4LtOaSiH4CjTWJqlX3/7+X2wlbonBCP5klZIigKltYgIhw== X-Received: by 2002:a2e:8957:: with SMTP id b23-v6mr12257099ljk.50.1535756152777; Fri, 31 Aug 2018 15:55:52 -0700 (PDT) Received: from localhost.localdomain (apn-37-248-212-140.dynamic.gprs.plus.pl. [37.248.212.140]) by smtp.gmail.com with ESMTPSA id v20-v6sm1969187ljc.94.2018.08.31.15.55.47 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 15:55:52 -0700 (PDT) From: Janusz Krzysztofik To: Linus Walleij Cc: Jonathan Corbet , Miguel Ojeda Sandonis , Peter Korsgaard , Peter Rosin , Ulf Hansson , Andrew Lunn , Florian Fainelli , "David S. Miller" , Dominik Brodowski , Greg Kroah-Hartman , Kishon Vijay Abraham I , Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , Hartmut Knaack , Peter Meerwald-Stadler , Jiri Slaby , Willy Tarreau , Geert Uytterhoeven , linux-doc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-mmc@vger.kernel.org, netdev@vger.kernel.org, linux-iio@vger.kernel.org, devel@driverdev.osuosl.org, linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Janusz Krzysztofik Subject: [PATCH v6 2/4] gpiolib: Identify arrays matching GPIO hardware Date: Sat, 1 Sep 2018 00:56:14 +0200 Message-Id: <20180831225616.29221-3-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180831225616.29221-1-jmkrzyszt@gmail.com> References: <20180829204900.19390-1-jmkrzyszt@gmail.com> <20180831225616.29221-1-jmkrzyszt@gmail.com> Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Certain GPIO array lookup results may map directly to GPIO pins of a single GPIO chip in hardware order. If that condition is recognized and handled efficiently, significant performance gain of get/set array functions may be possible. While processing a request for an array of GPIO descriptors, identify those which represent corresponding pins of a single GPIO chip. Skip over pins which require open source or open drain special processing. Moreover, identify pins which require inversion. Pass a pointer to that information with the array to the caller so it can benefit from enhanced performance as soon as get/set array functions can accept and make efficient use of it. Cc: Jonathan Corbet Signed-off-by: Janusz Krzysztofik --- Documentation/driver-api/gpio/consumer.rst | 4 +- drivers/gpio/gpiolib.c | 72 +++++++++++++++++++++++++++++- drivers/gpio/gpiolib.h | 9 ++++ include/linux/gpio/consumer.h | 9 ++++ 4 files changed, 92 insertions(+), 2 deletions(-) diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index ed68042ddccf..7e0298b9a7b9 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -109,9 +109,11 @@ For a function using multiple GPIOs all of those can be obtained with one call:: enum gpiod_flags flags) This function returns a struct gpio_descs which contains an array of -descriptors:: +descriptors. It also contains a pointer to a gpiolib private structure which, +if passed back to get/set array functions, may speed up I/O proocessing:: struct gpio_descs { + struct gpio_array *info; unsigned int ndescs; struct gpio_desc *desc[]; } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f0e9ffa8cab6..c1ed1c759345 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -4174,7 +4174,9 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, { struct gpio_desc *desc; struct gpio_descs *descs; - int count; + struct gpio_array *array_info = NULL; + struct gpio_chip *chip; + int count, bitmap_size; count = gpiod_count(dev, con_id); if (count < 0) @@ -4190,9 +4192,77 @@ struct gpio_descs *__must_check gpiod_get_array(struct device *dev, gpiod_put_array(descs); return ERR_CAST(desc); } + descs->desc[descs->ndescs] = desc; + + chip = gpiod_to_chip(desc); + /* + * Select a chip of first array member + * whose index matches its pin hardware number + * as a candidate for fast bitmap processing. + */ + if (!array_info && gpio_chip_hwgpio(desc) == descs->ndescs) { + struct gpio_descs *array; + + bitmap_size = BITS_TO_LONGS(chip->ngpio > count ? + chip->ngpio : count); + + array = kzalloc(struct_size(descs, desc, count) + + struct_size(array_info, invert_mask, + 3 * bitmap_size), GFP_KERNEL); + if (!array) { + gpiod_put_array(descs); + return ERR_PTR(-ENOMEM); + } + + memcpy(array, descs, + struct_size(descs, desc, descs->ndescs + 1)); + kfree(descs); + + descs = array; + array_info = (void *)(descs->desc + count); + array_info->get_mask = array_info->invert_mask + + bitmap_size; + array_info->set_mask = array_info->get_mask + + bitmap_size; + + array_info->desc = descs->desc; + array_info->size = count; + array_info->chip = chip; + bitmap_set(array_info->get_mask, descs->ndescs, + count - descs->ndescs); + bitmap_set(array_info->set_mask, descs->ndescs, + count - descs->ndescs); + descs->info = array_info; + } + /* + * Unmark members which don't qualify for fast bitmap + * processing (different chip, not in hardware order) + */ + if (array_info && (chip != array_info->chip || + gpio_chip_hwgpio(desc) != descs->ndescs)) { + __clear_bit(descs->ndescs, array_info->get_mask); + __clear_bit(descs->ndescs, array_info->set_mask); + } else if (array_info) { + /* Exclude open drain or open source from fast output */ + if (gpiochip_line_is_open_drain(chip, descs->ndescs) || + gpiochip_line_is_open_source(chip, descs->ndescs)) + __clear_bit(descs->ndescs, + array_info->set_mask); + /* Identify 'fast' pins which require invertion */ + if (gpiod_is_active_low(desc)) + __set_bit(descs->ndescs, + array_info->invert_mask); + } + descs->ndescs++; } + if (array_info) + dev_dbg(dev, + "GPIO array info: chip=%s, size=%d, get_mask=%lx, set_mask=%lx, invert_mask=%lx\n", + array_info->chip->label, array_info->size, + *array_info->get_mask, *array_info->set_mask, + *array_info->invert_mask); return descs; } EXPORT_SYMBOL_GPL(gpiod_get_array); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index 11e83d2eef89..b60905d558b1 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -183,6 +183,15 @@ static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev, } #endif +struct gpio_array { + struct gpio_desc **desc; + unsigned int size; + struct gpio_chip *chip; + unsigned long *get_mask; + unsigned long *set_mask; + unsigned long invert_mask[]; +}; + struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 1b21dc7b0fad..8dede3e886af 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -17,11 +17,20 @@ struct device; */ struct gpio_desc; +/** + * Opaque descriptor for a structure of GPIO array attributes. This structure + * is attached to struct gpiod_descs obtained from gpiod_get_array() and can be + * passed back to get/set array functions in order to activate fast processing + * path if applicable. + */ +struct gpio_array; + /** * Struct containing an array of descriptors that can be obtained using * gpiod_get_array(). */ struct gpio_descs { + struct gpio_array *info; unsigned int ndescs; struct gpio_desc *desc[]; }; From patchwork Fri Aug 31 22:56:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 10584575 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 BF412175A for ; Fri, 31 Aug 2018 22:56:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B043D2C1AE for ; Fri, 31 Aug 2018 22:56:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A33D42C6B9; Fri, 31 Aug 2018 22:56:26 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 657802C1AE for ; Fri, 31 Aug 2018 22:56:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727430AbeIADFo (ORCPT ); Fri, 31 Aug 2018 23:05:44 -0400 Received: from mail-lj1-f194.google.com ([209.85.208.194]:45738 "EHLO mail-lj1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727637AbeIADFo (ORCPT ); Fri, 31 Aug 2018 23:05:44 -0400 Received: by mail-lj1-f194.google.com with SMTP id u83-v6so11212788lje.12; Fri, 31 Aug 2018 15:56:01 -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=K483iNUnDl9kxW0BnODO4Sn+5nDYeGr7Vs01EaHpMis=; b=CJEEnwtgwUJWxl4JGs+uKgPW9qESDa9Tpb3wJ2HSC5Gc/ppi00SQNORMDkU2UdJjeH /hgJY/e8is1qPI8OAuZG9LG1y6uJYBmTThAMHuCM+LpCg6X3V23ycWMTjBBKYwH/znvB s1v+b0s1xYIEMLUTUZUfDLZztUzOSsZXvqkE6D0cm3pWW8/bdRK9xXdXXU5HrpOuIIVc 0G5wO90cUcTV0+oYXVXt/8fnCQ75oUG/sk1UqDKCZBcP9sXprH4S/0F0TS48NlHupqMn 2bNWhUqG68KfqUPIyEeU1txvLZChONfH6RBXu2IiwsC8S8o1VX4+NI/nOXPb1KTOUuV4 Z73w== 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=K483iNUnDl9kxW0BnODO4Sn+5nDYeGr7Vs01EaHpMis=; b=QOfp5QCL636iuVK8F9yV3GNB99dI+bpRu9uTmyN8+0pn5M5RyxghmXm7Ns6GAOSOmy oblsrR4kBmqL7h58CtAOgdpaclEUh255z4OF+iaDsE3g/fjBkpIUaD0UstfJhJ81t7Va kMhRLcLWLurJ8reK9mLwuodVwCVkK1oysXfcUPT43xr32wXrxF0P40Doe9Lsp3AGxl+W aDDVve/wdyrd2aI+Zz9ymNmb44SZAOpaqB/tP5Q+5oXX/gtAo9eXdsvfoYPmlr2DryJQ /aL9mQqk2/juIBTGi5Oz6cEvKYjDpgZUxeJ3fUR6Mqw+qLSORd8kZd/ILqIFQwB0wUtG jTiA== X-Gm-Message-State: APzg51BAXUg6VKL7pHQCvbKjleYevkVRq0A7cLa1QC9t0mb0/UekoWpa vN2n4AupjvEeebNMj4tP0p8= X-Google-Smtp-Source: ANB0VdaGOtRGbGqd2tUSAHDWfVmo1sgK7x2ifOFItQIzSNCcEK1laTEyoAeaUnv2iYh6DRAO1P1l0g== X-Received: by 2002:a2e:86c7:: with SMTP id n7-v6mr12181305ljj.90.1535756160987; Fri, 31 Aug 2018 15:56:00 -0700 (PDT) Received: from localhost.localdomain (apn-37-248-212-140.dynamic.gprs.plus.pl. [37.248.212.140]) by smtp.gmail.com with ESMTPSA id v20-v6sm1969187ljc.94.2018.08.31.15.55.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 15:56:00 -0700 (PDT) From: Janusz Krzysztofik To: Linus Walleij Cc: Jonathan Corbet , Miguel Ojeda Sandonis , Peter Korsgaard , Peter Rosin , Ulf Hansson , Andrew Lunn , Florian Fainelli , "David S. Miller" , Dominik Brodowski , Greg Kroah-Hartman , Kishon Vijay Abraham I , Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , Hartmut Knaack , Peter Meerwald-Stadler , Jiri Slaby , Willy Tarreau , Geert Uytterhoeven , linux-doc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-mmc@vger.kernel.org, netdev@vger.kernel.org, linux-iio@vger.kernel.org, devel@driverdev.osuosl.org, linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Janusz Krzysztofik Subject: [PATCH v6 3/4] gpiolib: Pass array info to get/set array functions Date: Sat, 1 Sep 2018 00:56:15 +0200 Message-Id: <20180831225616.29221-4-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180831225616.29221-1-jmkrzyszt@gmail.com> References: <20180829204900.19390-1-jmkrzyszt@gmail.com> <20180831225616.29221-1-jmkrzyszt@gmail.com> Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP In order to make use of array info obtained from gpiod_get_array() and speed up processing of arrays matching single GPIO chip layout, that information must be passed to get/set array functions. Extend the functions' API with that additional parameter and update all users. Pass NULL if a user bulids an array itself from single GPIOs. Cc: Jonathan Corbet Cc: Miguel Ojeda Sandonis Cc: Peter Korsgaard Cc: Peter Rosin Cc: Andrew Lunn Cc: Florian Fainelli Cc: "David S. Miller" Cc: Dominik Brodowski Cc: Kishon Vijay Abraham I Cc: Lars-Peter Clausen Cc: Michael Hennerich Cc: Jonathan Cameron Cc: Hartmut Knaack Cc: Peter Meerwald-Stadler Cc: Greg Kroah-Hartman Cc: Jiri Slaby Signed-off-by: Janusz Krzysztofik Acked-by: Ulf Hansson --- Documentation/driver-api/gpio/consumer.rst | 14 ++++++++++-- drivers/auxdisplay/hd44780.c | 12 ++++++---- drivers/bus/ts-nbus.c | 6 +++-- drivers/gpio/gpio-max3191x.c | 6 +++-- drivers/gpio/gpiolib.c | 34 ++++++++++++++++++++--------- drivers/gpio/gpiolib.h | 2 ++ drivers/i2c/muxes/i2c-mux-gpio.c | 2 +- drivers/mmc/core/pwrseq_simple.c | 2 +- drivers/mux/gpio.c | 3 ++- drivers/net/phy/mdio-mux-gpio.c | 2 +- drivers/pcmcia/soc_common.c | 3 ++- drivers/phy/motorola/phy-mapphone-mdm6600.c | 4 +++- drivers/staging/iio/adc/ad7606.c | 3 ++- drivers/tty/serial/serial_mctrl_gpio.c | 2 +- include/linux/gpio/consumer.h | 8 +++++++ 15 files changed, 75 insertions(+), 28 deletions(-) diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index 7e0298b9a7b9..0afd95a12b10 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -325,28 +325,36 @@ The following functions get or set the values of an array of GPIOs:: int gpiod_get_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); int gpiod_get_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) void gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) void gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) The array can be an arbitrary set of GPIOs. The functions will try to access @@ -358,6 +366,7 @@ accessed sequentially. The functions take three arguments: * array_size - the number of array elements * desc_array - an array of GPIO descriptors + * array_info - optional information obtained from gpiod_array_get() * value_bitmap - a bitmap to store the GPIOs' values (get) or a bitmap of values to assign to the GPIOs (set) @@ -368,12 +377,13 @@ the struct gpio_descs returned by gpiod_get_array():: struct gpio_descs *my_gpio_descs = gpiod_get_array(...); gpiod_set_array_value(my_gpio_descs->ndescs, my_gpio_descs->desc, - my_gpio_value_bitmap); + my_gpio_descs->info, my_gpio_value_bitmap); It is also possible to access a completely arbitrary array of descriptors. The descriptors may be obtained using any combination of gpiod_get() and gpiod_get_array(). Afterwards the array of descriptors has to be setup -manually before it can be passed to one of the above functions. +manually before it can be passed to one of the above functions. In that case, +array_info should be set to NULL. Note that for optimal performance GPIOs belonging to the same chip should be contiguous within the array of descriptors. diff --git a/drivers/auxdisplay/hd44780.c b/drivers/auxdisplay/hd44780.c index 7ee4f9a65bfc..4134fd090206 100644 --- a/drivers/auxdisplay/hd44780.c +++ b/drivers/auxdisplay/hd44780.c @@ -70,7 +70,8 @@ static void hd44780_write_gpio8(struct hd44780 *hd, u8 val, unsigned int rs) n = hd->pins[PIN_CTRL_RW] ? 10 : 9; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], value_bitmap); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA0], NULL, + value_bitmap); hd44780_strobe_gpio(hd); } @@ -87,7 +88,8 @@ static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, + value_bitmap); hd44780_strobe_gpio(hd); @@ -96,7 +98,8 @@ static void hd44780_write_gpio4(struct hd44780 *hd, u8 val, unsigned int rs) *value_bitmap |= val & 0x0f; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, + value_bitmap); hd44780_strobe_gpio(hd); } @@ -153,7 +156,8 @@ static void hd44780_write_cmd_raw_gpio4(struct charlcd *lcd, int cmd) n = hd->pins[PIN_CTRL_RW] ? 6 : 5; /* Present the data to the port */ - gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], value_bitmap); + gpiod_set_array_value_cansleep(n, &hd->pins[PIN_DATA4], NULL, + value_bitmap); hd44780_strobe_gpio(hd); } diff --git a/drivers/bus/ts-nbus.c b/drivers/bus/ts-nbus.c index 2ac5239df865..0a8fa64a4050 100644 --- a/drivers/bus/ts-nbus.c +++ b/drivers/bus/ts-nbus.c @@ -114,7 +114,8 @@ static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus) *value_bitmap = 0; - gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, value_bitmap); + gpiod_set_array_value_cansleep(8, ts_nbus->data->desc, + ts_nbus->data->info, value_bitmap); gpiod_set_value_cansleep(ts_nbus->csn, 0); gpiod_set_value_cansleep(ts_nbus->strobe, 0); gpiod_set_value_cansleep(ts_nbus->ale, 0); @@ -157,7 +158,8 @@ static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte) struct gpio_descs *gpios = ts_nbus->data; DECLARE_BITMAP(value_bitmap, 8) = { byte, }; - gpiod_set_array_value_cansleep(8, gpios->desc, value_bitmap); + gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, + value_bitmap); } /* diff --git a/drivers/gpio/gpio-max3191x.c b/drivers/gpio/gpio-max3191x.c index c4ec1c82af27..4b43b5dabfd2 100644 --- a/drivers/gpio/gpio-max3191x.c +++ b/drivers/gpio/gpio-max3191x.c @@ -313,6 +313,7 @@ static int max3191x_set_config(struct gpio_chip *gpio, unsigned int offset, static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, struct gpio_desc **desc, + struct gpio_array *info, int value) { unsigned long *value_bitmap; @@ -327,7 +328,7 @@ static void gpiod_set_array_single_value_cansleep(unsigned int ndescs, else bitmap_zero(value_bitmap, ndescs); - gpiod_set_array_value_cansleep(ndescs, desc, value_bitmap); + gpiod_set_array_value_cansleep(ndescs, desc, info, value_bitmap); kfree(value_bitmap); } @@ -400,7 +401,8 @@ static int max3191x_probe(struct spi_device *spi) if (max3191x->modesel_pins) gpiod_set_array_single_value_cansleep( max3191x->modesel_pins->ndescs, - max3191x->modesel_pins->desc, max3191x->mode); + max3191x->modesel_pins->desc, + max3191x->modesel_pins->info, max3191x->mode); max3191x->ignore_uv = device_property_read_bool(dev, "maxim,ignore-undervoltage"); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c1ed1c759345..4d26cdbdb7cf 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -435,7 +435,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, int ret = gpiod_get_array_value_complex(false, true, lh->numdescs, - lh->descs, + lh->descs, NULL, value_bitmap); if (ret) return ret; @@ -467,7 +467,7 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, return gpiod_set_array_value_complex(false, true, lh->numdescs, - lh->descs, + lh->descs, NULL, value_bitmap); } return -EINVAL; @@ -2784,6 +2784,7 @@ static int gpio_chip_get_multiple(struct gpio_chip *chip, int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { int i = 0; @@ -2908,12 +2909,14 @@ EXPORT_SYMBOL_GPL(gpiod_get_value); */ int gpiod_get_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, false, array_size, - desc_array, value_bitmap); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); @@ -2931,12 +2934,14 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value); */ int gpiod_get_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, false, array_size, - desc_array, value_bitmap); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value); @@ -3029,6 +3034,7 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip, int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { int i = 0; @@ -3166,12 +3172,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_value); */ int gpiod_set_raw_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, false, array_size, - desc_array, value_bitmap); + desc_array, array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); @@ -3189,12 +3196,13 @@ EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value); */ void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { if (!desc_array) return; gpiod_set_array_value_complex(false, false, array_size, desc_array, - value_bitmap); + array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value); @@ -3426,13 +3434,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_value_cansleep); */ int gpiod_get_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(true, true, array_size, - desc_array, value_bitmap); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); @@ -3449,13 +3459,15 @@ EXPORT_SYMBOL_GPL(gpiod_get_raw_array_value_cansleep); */ int gpiod_get_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_get_array_value_complex(false, true, array_size, - desc_array, value_bitmap); + desc_array, array_info, + value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_get_array_value_cansleep); @@ -3508,13 +3520,14 @@ EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); */ int gpiod_set_raw_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return -EINVAL; return gpiod_set_array_value_complex(true, true, array_size, desc_array, - value_bitmap); + array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep); @@ -3548,13 +3561,14 @@ void gpiod_add_lookup_tables(struct gpiod_lookup_table **tables, size_t n) */ void gpiod_set_array_value_cansleep(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap) { might_sleep_if(extra_checks); if (!desc_array) return; gpiod_set_array_value_complex(false, true, array_size, desc_array, - value_bitmap); + array_info, value_bitmap); } EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b60905d558b1..b65ca896b24d 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -196,10 +196,12 @@ struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum); int gpiod_get_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); int gpiod_set_array_value_complex(bool raw, bool can_sleep, unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); /* This is just passed between gpiolib and devres */ diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index e28ddc20000d..ac77519d4a82 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -31,7 +31,7 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) *value_bitmap = val; gpiod_set_array_value_cansleep(mux->data.n_gpios, - mux->gpios, value_bitmap); + mux->gpios, NULL, value_bitmap); } static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c index fd7791e072b3..a57f8a7d5266 100644 --- a/drivers/mmc/core/pwrseq_simple.c +++ b/drivers/mmc/core/pwrseq_simple.c @@ -46,7 +46,7 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq, *value_bitmap = value; gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, - value_bitmap); + reset_gpios->info, value_bitmap); } } diff --git a/drivers/mux/gpio.c b/drivers/mux/gpio.c index 17b7b1c21d90..728323207b8c 100644 --- a/drivers/mux/gpio.c +++ b/drivers/mux/gpio.c @@ -27,7 +27,8 @@ static int mux_gpio_set(struct mux_control *mux, int state) *value_bitmap = state; gpiod_set_array_value_cansleep(mux_gpio->gpios->ndescs, - mux_gpio->gpios->desc, value_bitmap); + mux_gpio->gpios->desc, + mux_gpio->gpios->info, value_bitmap); return 0; } diff --git a/drivers/net/phy/mdio-mux-gpio.c b/drivers/net/phy/mdio-mux-gpio.c index 3907e9528949..42f5c253b62c 100644 --- a/drivers/net/phy/mdio-mux-gpio.c +++ b/drivers/net/phy/mdio-mux-gpio.c @@ -34,7 +34,7 @@ static int mdio_mux_gpio_switch_fn(int current_child, int desired_child, *value_bitmap = desired_child; gpiod_set_array_value_cansleep(s->gpios->ndescs, s->gpios->desc, - value_bitmap); + s->gpios->info, value_bitmap); return 0; } diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 44288b1a57ee..75c3e0bb2737 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c @@ -366,7 +366,8 @@ static int soc_common_pcmcia_config_skt( } if (n) - gpiod_set_array_value_cansleep(n, descs, value_bitmap); + gpiod_set_array_value_cansleep(n, descs, NULL, + value_bitmap); /* * This really needs a better solution. The IRQ diff --git a/drivers/phy/motorola/phy-mapphone-mdm6600.c b/drivers/phy/motorola/phy-mapphone-mdm6600.c index b348272f7f1a..5611a04bc286 100644 --- a/drivers/phy/motorola/phy-mapphone-mdm6600.c +++ b/drivers/phy/motorola/phy-mapphone-mdm6600.c @@ -162,7 +162,8 @@ static void phy_mdm6600_cmd(struct phy_mdm6600 *ddata, int val) *value_bitmap = val & ((1 << PHY_MDM6600_NR_CMD_LINES) - 1); gpiod_set_array_value_cansleep(PHY_MDM6600_NR_CMD_LINES, - ddata->cmd_gpios->desc, value_bitmap); + ddata->cmd_gpios->desc, + ddata->cmd_gpios->info, value_bitmap); } /** @@ -181,6 +182,7 @@ static void phy_mdm6600_status(struct work_struct *work) error = gpiod_get_array_value_cansleep(PHY_MDM6600_NR_STATUS_LINES, ddata->status_gpios->desc, + ddata->status_gpios->info, value_bitmap); if (error) return; diff --git a/drivers/staging/iio/adc/ad7606.c b/drivers/staging/iio/adc/ad7606.c index 18b6d10b0176..9115b5ee3601 100644 --- a/drivers/staging/iio/adc/ad7606.c +++ b/drivers/staging/iio/adc/ad7606.c @@ -230,7 +230,8 @@ static int ad7606_write_raw(struct iio_dev *indio_dev, *value_bitmap = ret; mutex_lock(&st->lock); - gpiod_set_array_value(3, st->gpio_os->desc, value_bitmap); + gpiod_set_array_value(3, st->gpio_os->desc, st->gpio_os->info, + value_bitmap); st->oversampling = val; mutex_unlock(&st->lock); diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c index edfe8c688479..66408108a951 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -53,7 +53,7 @@ void mctrl_gpio_set(struct mctrl_gpios *gpios, unsigned int mctrl) !!(mctrl & mctrl_gpios_desc[i].mctrl)); count++; } - gpiod_set_array_value(count, desc_array, value_bitmap); + gpiod_set_array_value(count, desc_array, NULL, value_bitmap); } EXPORT_SYMBOL_GPL(mctrl_gpio_set); diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index 8dede3e886af..bf037ebe2ed8 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -114,36 +114,44 @@ 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, + struct gpio_array *array_info, unsigned long *value_bitmap); void gpiod_set_value(struct gpio_desc *desc, int value); void gpiod_set_array_value(unsigned int array_size, struct gpio_desc **desc_array, + struct gpio_array *array_info, unsigned long *value_bitmap); 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, + struct gpio_array *array_info, unsigned long *value_bitmap); 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, + struct gpio_array *array_info, unsigned long *value_bitmap); /* 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, + struct gpio_array *array_info, unsigned long *value_bitmap); 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, + struct gpio_array *array_info, unsigned long *value_bitmap); 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, + struct gpio_array *array_info, unsigned long *value_bitmap); 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, + struct gpio_array *array_info, unsigned long *value_bitmap); int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce); From patchwork Fri Aug 31 22:56: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: 10584573 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 13E8E5A4 for ; Fri, 31 Aug 2018 22:56:23 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 059EA2C1AE for ; Fri, 31 Aug 2018 22:56:23 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id ECBE62C6B9; Fri, 31 Aug 2018 22:56:22 +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=-8.0 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 53A332C1AE for ; Fri, 31 Aug 2018 22:56:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727848AbeIADFt (ORCPT ); Fri, 31 Aug 2018 23:05:49 -0400 Received: from mail-lj1-f193.google.com ([209.85.208.193]:41821 "EHLO mail-lj1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727637AbeIADFt (ORCPT ); Fri, 31 Aug 2018 23:05:49 -0400 Received: by mail-lj1-f193.google.com with SMTP id y17-v6so11255908ljy.8; Fri, 31 Aug 2018 15:56:07 -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=uh7mqvxXnjaw9WCsqO1jdthyZWLvGWRFnitWjcEgjoA=; b=HQj4SGKNgs8f9iXKtGvns961NWAptusN3lWLpFVfdPo0Qcxm6Q2aePZ8b92Pdkjli4 f+pmlZugPzTlMQZPn//LwII//kLmU/cJrk3xhqLa9dNblTA71v7/M+Uf/kseKSDhWfj8 jpdaC46O4e/lS0oN6c5B+/o8xBAq+vZxlHIXsR8cuFdx8eIjFI3E3P+XhFWQSMTZbEhF nFuJ8+Ii6agbid3pdfXbKl/HG7TI9Sm392Lai/k81stI5cWJhC6YXC6a02JoPw/gYpka +SxglCsr1Fa3Nk70WW4t1ScRefu6Z9Qxbpl9jEZ3jGyrtx60ry+iPjXIgjlVFXUwlbmJ kRZg== 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=uh7mqvxXnjaw9WCsqO1jdthyZWLvGWRFnitWjcEgjoA=; b=pUMGlb8r7hFCyW0GWH8OckNKkK6/wqVfR2ny+Qcdtlp7zYXAuS2YsfGllRlpACY/Tt 7BC2l91qwt9RT+hXsozxDpsF4LdxJlOj8gaWLkNqMKtdruFLb/JhRZVKYglvr4Ez8gu/ VYBi/VfwCawYpKPJ9RwHglDDylg0htDU11eSo2lZEsX0//biAkf7MII2pvML3H+jfF2E YUswXrak6l8DxfcHnOOVzSdJ6e7Uq364OF41aHVEup+MoWC8phQjOxNNidgvR22B5VoU s2Ak/qhhFy8aqLa/UaWU96o9Oftl3m0ccQatN+AZYz/qUcIVx592Mskf3w34zJcG5Pb6 3tsA== X-Gm-Message-State: APzg51BLaAZYsyrNjjzCA/G8H5+yMAe//SfDYGWeZSJTXCD015MvnwvC OMP9Bsnt2f35cdz2q4a8mdU= X-Google-Smtp-Source: ANB0VdYdQRK6Bou/NoJzk2IpPD7A6aa7x5dPB+XpbFgej7tf/vG0Hl9aZzM93U05I+aQRGsAcceLgA== X-Received: by 2002:a2e:610a:: with SMTP id v10-v6mr11343517ljb.39.1535756166923; Fri, 31 Aug 2018 15:56:06 -0700 (PDT) Received: from localhost.localdomain (apn-37-248-212-140.dynamic.gprs.plus.pl. [37.248.212.140]) by smtp.gmail.com with ESMTPSA id v20-v6sm1969187ljc.94.2018.08.31.15.56.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 31 Aug 2018 15:56:06 -0700 (PDT) From: Janusz Krzysztofik To: Linus Walleij Cc: Jonathan Corbet , Miguel Ojeda Sandonis , Peter Korsgaard , Peter Rosin , Ulf Hansson , Andrew Lunn , Florian Fainelli , "David S. Miller" , Dominik Brodowski , Greg Kroah-Hartman , Kishon Vijay Abraham I , Lars-Peter Clausen , Michael Hennerich , Jonathan Cameron , Hartmut Knaack , Peter Meerwald-Stadler , Jiri Slaby , Willy Tarreau , Geert Uytterhoeven , linux-doc@vger.kernel.org, linux-i2c@vger.kernel.org, linux-mmc@vger.kernel.org, netdev@vger.kernel.org, linux-iio@vger.kernel.org, devel@driverdev.osuosl.org, linux-serial@vger.kernel.org, linux-gpio@vger.kernel.org, linux-kernel@vger.kernel.org, Janusz Krzysztofik Subject: [PATCH v6 4/4] gpiolib: Implement fast processing path in get/set array Date: Sat, 1 Sep 2018 00:56:16 +0200 Message-Id: <20180831225616.29221-5-jmkrzyszt@gmail.com> X-Mailer: git-send-email 2.16.4 In-Reply-To: <20180831225616.29221-1-jmkrzyszt@gmail.com> References: <20180829204900.19390-1-jmkrzyszt@gmail.com> <20180831225616.29221-1-jmkrzyszt@gmail.com> Sender: linux-iio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-iio@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Certain GPIO descriptor arrays returned by gpio_get_array() may contain information on direct mapping of array members to pins of a single GPIO chip in hardware order. In such cases, bitmaps of values can be passed directly from/to the chip's .get/set_multiple() callbacks without wasting time on iterations. Add respective code to gpiod_get/set_array_bitmap_complex() functions. Pins not applicable for fast path are processed as before, skipping over the 'fast' ones. Cc: Jonathan Corbet Signed-off-by: Janusz Krzysztofik --- Documentation/driver-api/gpio/board.rst | 15 ++++++ Documentation/driver-api/gpio/consumer.rst | 8 +++ drivers/gpio/gpiolib.c | 87 ++++++++++++++++++++++++++++-- 3 files changed, 105 insertions(+), 5 deletions(-) diff --git a/Documentation/driver-api/gpio/board.rst b/Documentation/driver-api/gpio/board.rst index 2c112553df84..c66821e033c2 100644 --- a/Documentation/driver-api/gpio/board.rst +++ b/Documentation/driver-api/gpio/board.rst @@ -193,3 +193,18 @@ And the table can be added to the board code as follows:: The line will be hogged as soon as the gpiochip is created or - in case the chip was created earlier - when the hog table is registered. + +Arrays of pins +-------------- +In addition to requesting pins belonging to a function one by one, a device may +also request an array of pins assigned to the function. The way those pins are +mapped to the device determines if the array qualifies for fast bitmap +processing. If yes, a bitmap is passed over get/set array functions directly +between a caller and a respective .get/set_multiple() callback of a GPIO chip. + +In order to qualify for fast bitmap processing, the pin mapping must meet the +following requirements: +- it must belong to the same chip as other 'fast' pins of the function, +- its index within the function must match its hardware number within the chip. + +Open drain and open source pins are excluded from fast bitmap output processing. diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index 0afd95a12b10..cf992e5ab976 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -388,6 +388,14 @@ array_info should be set to NULL. Note that for optimal performance GPIOs belonging to the same chip should be contiguous within the array of descriptors. +Still better performance may be achieved if array indexes of the descriptors +match hardware pin numbers of a single chip. If an array passed to a get/set +array function matches the one obtained from gpiod_get_array() and array_info +associated with the array is also passed, the function may take a fast bitmap +processing path, passing the value_bitmap argument directly to the respective +.get/set_multiple() callback of the chip. That allows for utilization of GPIO +banks as data I/O ports without much loss of performance. + The return value of gpiod_get_array_value() and its variants is 0 on success 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 diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 4d26cdbdb7cf..b799a89c4c17 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2787,7 +2787,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, struct gpio_array *array_info, unsigned long *value_bitmap) { - int i = 0; + int err, i = 0; + + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + err = gpio_chip_get_multiple(array_info->chip, + array_info->get_mask, + value_bitmap); + if (err) + return err; + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + if (bitmap_full(array_info->get_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->get_mask, array_size); + } else { + array_info = NULL; + } while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; @@ -2818,7 +2847,12 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); __set_bit(hwgpio, mask); - i++; + + if (array_info) + find_next_zero_bit(array_info->get_mask, + array_size, i); + else + i++; } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); @@ -2829,7 +2863,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, return ret; } - for (j = first; j < i; j++) { + for (j = first; j < i; ) { const struct gpio_desc *desc = desc_array[j]; int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(hwgpio, bits); @@ -2838,6 +2872,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep, value = !value; __assign_bit(j, value_bitmap, value); trace_gpio_value(desc_to_gpio(desc), 1, value); + + if (array_info) + find_next_zero_bit(array_info->get_mask, i, j); + else + j++; } if (mask != fastpath) @@ -3039,6 +3078,32 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, { int i = 0; + /* + * Validate array_info against desc_array and its size. + * It should immediately follow desc_array if both + * have been obtained from the same gpiod_get_array() call. + */ + if (array_info && array_info->desc == desc_array && + array_size <= array_info->size && + (void *)array_info == desc_array + array_info->size) { + if (!can_sleep) + WARN_ON(array_info->chip->can_sleep); + + if (!raw && !bitmap_empty(array_info->invert_mask, array_size)) + bitmap_xor(value_bitmap, value_bitmap, + array_info->invert_mask, array_size); + + gpio_chip_set_multiple(array_info->chip, array_info->set_mask, + value_bitmap); + + if (bitmap_full(array_info->set_mask, array_size)) + return 0; + + i = find_first_zero_bit(array_info->set_mask, array_size); + } else { + array_info = NULL; + } + while (i < array_size) { struct gpio_chip *chip = desc_array[i]->gdev->chip; unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; @@ -3066,7 +3131,14 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, int hwgpio = gpio_chip_hwgpio(desc); int value = test_bit(i, value_bitmap); - if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) + /* + * Pins applicable for fast input but not for + * fast output processing may have been already + * inverted inside the fast path, skip them. + */ + if (!raw && !(array_info && + test_bit(i, array_info->invert_mask)) && + test_bit(FLAG_ACTIVE_LOW, &desc->flags)) value = !value; trace_gpio_value(desc_to_gpio(desc), 0, value); /* @@ -3085,7 +3157,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep, __clear_bit(hwgpio, bits); count++; } - i++; + + if (array_info) + find_next_zero_bit(array_info->set_mask, + array_size, i); + else + i++; } while ((i < array_size) && (desc_array[i]->gdev->chip == chip)); /* push collected bits to outputs */