Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

gpio: omap: return error if requested debounce time is not possible

omap_gpio_debounce() does not validate that the requested debounce
is within a range it can handle. Instead it lets the register value
wrap silently, and always returns success.

This can lead to all sorts of unexpected behavior, such as gpio_keys
asking for a too-long debounce, but getting a very short debounce in
practice.

Fix this by returning -EINVAL if the requested value does not fit into
the register field. If there is no debounce clock available at all,
return -ENOTSUPP.

Fixes: e85ec6c3047b ("gpio: omap: fix omap2_set_gpio_debounce")
Cc: <stable@vger.kernel.org> # 4.3+
Signed-off-by: David Rivshin <drivshin@allworx.com>
Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>

authored by

David Rivshin and committed by
Linus Walleij
83977443 93847930

+17 -6
+17 -6
drivers/gpio/gpio-omap.c
··· 208 208 * OMAP's debounce time is in 31us steps 209 209 * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 210 210 * so we need to convert and round up to the closest unit. 211 + * 212 + * Return: 0 on success, negative error otherwise. 211 213 */ 212 - static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, 213 - unsigned debounce) 214 + static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, 215 + unsigned debounce) 214 216 { 215 217 void __iomem *reg; 216 218 u32 val; ··· 220 218 bool enable = !!debounce; 221 219 222 220 if (!bank->dbck_flag) 223 - return; 221 + return -ENOTSUPP; 224 222 225 223 if (enable) { 226 224 debounce = DIV_ROUND_UP(debounce, 31) - 1; 227 - debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; 225 + if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) 226 + return -EINVAL; 228 227 } 229 228 230 229 l = BIT(offset); ··· 258 255 bank->context.debounce = debounce; 259 256 bank->context.debounce_en = val; 260 257 } 258 + 259 + return 0; 261 260 } 262 261 263 262 /** ··· 969 964 { 970 965 struct gpio_bank *bank; 971 966 unsigned long flags; 967 + int ret; 972 968 973 969 bank = gpiochip_get_data(chip); 974 970 975 971 raw_spin_lock_irqsave(&bank->lock, flags); 976 - omap2_set_gpio_debounce(bank, offset, debounce); 972 + ret = omap2_set_gpio_debounce(bank, offset, debounce); 977 973 raw_spin_unlock_irqrestore(&bank->lock, flags); 978 974 979 - return 0; 975 + if (ret) 976 + dev_info(chip->parent, 977 + "Could not set line %u debounce to %u microseconds (%d)", 978 + offset, debounce, ret); 979 + 980 + return ret; 980 981 } 981 982 982 983 static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset,