diff options
author | David Rivshin <DRivshin@allworx.com> | 2017-04-24 18:56:50 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2017-04-28 03:50:22 -0400 |
commit | 83977443938122baeed28dc9f078db3da9855f7c (patch) | |
tree | d2a5106491740b2c8330a8de9a3d3c6badfe6cda /drivers/gpio/gpio-omap.c | |
parent | 9384793036afb7529c1c564e839ef4356271d68e (diff) |
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>
Diffstat (limited to 'drivers/gpio/gpio-omap.c')
-rw-r--r-- | drivers/gpio/gpio-omap.c | 23 |
1 files changed, 17 insertions, 6 deletions
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 5d6a5744352f..f8c550de6c72 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c | |||
@@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) | |||
208 | * OMAP's debounce time is in 31us steps | 208 | * OMAP's debounce time is in 31us steps |
209 | * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 | 209 | * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 |
210 | * so we need to convert and round up to the closest unit. | 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, | 214 | static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, |
213 | unsigned debounce) | 215 | unsigned debounce) |
214 | { | 216 | { |
215 | void __iomem *reg; | 217 | void __iomem *reg; |
216 | u32 val; | 218 | u32 val; |
@@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, | |||
218 | bool enable = !!debounce; | 220 | bool enable = !!debounce; |
219 | 221 | ||
220 | if (!bank->dbck_flag) | 222 | if (!bank->dbck_flag) |
221 | return; | 223 | return -ENOTSUPP; |
222 | 224 | ||
223 | if (enable) { | 225 | if (enable) { |
224 | debounce = DIV_ROUND_UP(debounce, 31) - 1; | 226 | debounce = DIV_ROUND_UP(debounce, 31) - 1; |
225 | debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; | 227 | if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) |
228 | return -EINVAL; | ||
226 | } | 229 | } |
227 | 230 | ||
228 | l = BIT(offset); | 231 | l = BIT(offset); |
@@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, | |||
255 | bank->context.debounce = debounce; | 258 | bank->context.debounce = debounce; |
256 | bank->context.debounce_en = val; | 259 | bank->context.debounce_en = val; |
257 | } | 260 | } |
261 | |||
262 | return 0; | ||
258 | } | 263 | } |
259 | 264 | ||
260 | /** | 265 | /** |
@@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, | |||
964 | { | 969 | { |
965 | struct gpio_bank *bank; | 970 | struct gpio_bank *bank; |
966 | unsigned long flags; | 971 | unsigned long flags; |
972 | int ret; | ||
967 | 973 | ||
968 | bank = gpiochip_get_data(chip); | 974 | bank = gpiochip_get_data(chip); |
969 | 975 | ||
970 | raw_spin_lock_irqsave(&bank->lock, flags); | 976 | raw_spin_lock_irqsave(&bank->lock, flags); |
971 | omap2_set_gpio_debounce(bank, offset, debounce); | 977 | ret = omap2_set_gpio_debounce(bank, offset, debounce); |
972 | raw_spin_unlock_irqrestore(&bank->lock, flags); | 978 | raw_spin_unlock_irqrestore(&bank->lock, flags); |
973 | 979 | ||
974 | return 0; | 980 | if (ret) |
981 | dev_info(chip->parent, | ||
982 | "Could not set line %u debounce to %u microseconds (%d)", | ||
983 | offset, debounce, ret); | ||
984 | |||
985 | return ret; | ||
975 | } | 986 | } |
976 | 987 | ||
977 | static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset, | 988 | static int omap_gpio_set_config(struct gpio_chip *chip, unsigned offset, |