aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorJanusz Krzysztofik <jmkrzyszt@gmail.com>2018-09-05 17:50:08 -0400
committerLinus Walleij <linus.walleij@linaro.org>2018-09-13 05:17:23 -0400
commitb17566a6b08be18ded5472a2e4bbc066593b3662 (patch)
tree855c1933616c99b7b7998be6e5e5a88dc490d5a4 /drivers/gpio
parent77588c14ac868caece82fddbfae7de03b2cec941 (diff)
gpiolib: Implement fast processing path in get/set array
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 <corbet@lwn.net> Signed-off-by: Janusz Krzysztofik <jmkrzyszt@gmail.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c87
1 files changed, 82 insertions, 5 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index cd7c1deed132..d7532aa6c0bc 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -2789,7 +2789,36 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
2789 struct gpio_array *array_info, 2789 struct gpio_array *array_info,
2790 unsigned long *value_bitmap) 2790 unsigned long *value_bitmap)
2791{ 2791{
2792 int i = 0; 2792 int err, i = 0;
2793
2794 /*
2795 * Validate array_info against desc_array and its size.
2796 * It should immediately follow desc_array if both
2797 * have been obtained from the same gpiod_get_array() call.
2798 */
2799 if (array_info && array_info->desc == desc_array &&
2800 array_size <= array_info->size &&
2801 (void *)array_info == desc_array + array_info->size) {
2802 if (!can_sleep)
2803 WARN_ON(array_info->chip->can_sleep);
2804
2805 err = gpio_chip_get_multiple(array_info->chip,
2806 array_info->get_mask,
2807 value_bitmap);
2808 if (err)
2809 return err;
2810
2811 if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
2812 bitmap_xor(value_bitmap, value_bitmap,
2813 array_info->invert_mask, array_size);
2814
2815 if (bitmap_full(array_info->get_mask, array_size))
2816 return 0;
2817
2818 i = find_first_zero_bit(array_info->get_mask, array_size);
2819 } else {
2820 array_info = NULL;
2821 }
2793 2822
2794 while (i < array_size) { 2823 while (i < array_size) {
2795 struct gpio_chip *chip = desc_array[i]->gdev->chip; 2824 struct gpio_chip *chip = desc_array[i]->gdev->chip;
@@ -2820,7 +2849,12 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
2820 int hwgpio = gpio_chip_hwgpio(desc); 2849 int hwgpio = gpio_chip_hwgpio(desc);
2821 2850
2822 __set_bit(hwgpio, mask); 2851 __set_bit(hwgpio, mask);
2823 i++; 2852
2853 if (array_info)
2854 find_next_zero_bit(array_info->get_mask,
2855 array_size, i);
2856 else
2857 i++;
2824 } while ((i < array_size) && 2858 } while ((i < array_size) &&
2825 (desc_array[i]->gdev->chip == chip)); 2859 (desc_array[i]->gdev->chip == chip));
2826 2860
@@ -2831,7 +2865,7 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
2831 return ret; 2865 return ret;
2832 } 2866 }
2833 2867
2834 for (j = first; j < i; j++) { 2868 for (j = first; j < i; ) {
2835 const struct gpio_desc *desc = desc_array[j]; 2869 const struct gpio_desc *desc = desc_array[j];
2836 int hwgpio = gpio_chip_hwgpio(desc); 2870 int hwgpio = gpio_chip_hwgpio(desc);
2837 int value = test_bit(hwgpio, bits); 2871 int value = test_bit(hwgpio, bits);
@@ -2840,6 +2874,11 @@ int gpiod_get_array_value_complex(bool raw, bool can_sleep,
2840 value = !value; 2874 value = !value;
2841 __assign_bit(j, value_bitmap, value); 2875 __assign_bit(j, value_bitmap, value);
2842 trace_gpio_value(desc_to_gpio(desc), 1, value); 2876 trace_gpio_value(desc_to_gpio(desc), 1, value);
2877
2878 if (array_info)
2879 find_next_zero_bit(array_info->get_mask, i, j);
2880 else
2881 j++;
2843 } 2882 }
2844 2883
2845 if (mask != fastpath) 2884 if (mask != fastpath)
@@ -3043,6 +3082,32 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
3043{ 3082{
3044 int i = 0; 3083 int i = 0;
3045 3084
3085 /*
3086 * Validate array_info against desc_array and its size.
3087 * It should immediately follow desc_array if both
3088 * have been obtained from the same gpiod_get_array() call.
3089 */
3090 if (array_info && array_info->desc == desc_array &&
3091 array_size <= array_info->size &&
3092 (void *)array_info == desc_array + array_info->size) {
3093 if (!can_sleep)
3094 WARN_ON(array_info->chip->can_sleep);
3095
3096 if (!raw && !bitmap_empty(array_info->invert_mask, array_size))
3097 bitmap_xor(value_bitmap, value_bitmap,
3098 array_info->invert_mask, array_size);
3099
3100 gpio_chip_set_multiple(array_info->chip, array_info->set_mask,
3101 value_bitmap);
3102
3103 if (bitmap_full(array_info->set_mask, array_size))
3104 return 0;
3105
3106 i = find_first_zero_bit(array_info->set_mask, array_size);
3107 } else {
3108 array_info = NULL;
3109 }
3110
3046 while (i < array_size) { 3111 while (i < array_size) {
3047 struct gpio_chip *chip = desc_array[i]->gdev->chip; 3112 struct gpio_chip *chip = desc_array[i]->gdev->chip;
3048 unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)]; 3113 unsigned long fastpath[2 * BITS_TO_LONGS(FASTPATH_NGPIO)];
@@ -3070,7 +3135,14 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
3070 int hwgpio = gpio_chip_hwgpio(desc); 3135 int hwgpio = gpio_chip_hwgpio(desc);
3071 int value = test_bit(i, value_bitmap); 3136 int value = test_bit(i, value_bitmap);
3072 3137
3073 if (!raw && test_bit(FLAG_ACTIVE_LOW, &desc->flags)) 3138 /*
3139 * Pins applicable for fast input but not for
3140 * fast output processing may have been already
3141 * inverted inside the fast path, skip them.
3142 */
3143 if (!raw && !(array_info &&
3144 test_bit(i, array_info->invert_mask)) &&
3145 test_bit(FLAG_ACTIVE_LOW, &desc->flags))
3074 value = !value; 3146 value = !value;
3075 trace_gpio_value(desc_to_gpio(desc), 0, value); 3147 trace_gpio_value(desc_to_gpio(desc), 0, value);
3076 /* 3148 /*
@@ -3089,7 +3161,12 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
3089 __clear_bit(hwgpio, bits); 3161 __clear_bit(hwgpio, bits);
3090 count++; 3162 count++;
3091 } 3163 }
3092 i++; 3164
3165 if (array_info)
3166 find_next_zero_bit(array_info->set_mask,
3167 array_size, i);
3168 else
3169 i++;
3093 } while ((i < array_size) && 3170 } while ((i < array_size) &&
3094 (desc_array[i]->gdev->chip == chip)); 3171 (desc_array[i]->gdev->chip == chip));
3095 /* push collected bits to outputs */ 3172 /* push collected bits to outputs */