]>
Commit | Line | Data |
---|---|---|
899c9bca GKH |
1 | From 83977443938122baeed28dc9f078db3da9855f7c Mon Sep 17 00:00:00 2001 |
2 | From: David Rivshin <DRivshin@allworx.com> | |
3 | Date: Mon, 24 Apr 2017 18:56:50 -0400 | |
4 | Subject: gpio: omap: return error if requested debounce time is not possible | |
5 | ||
6 | From: David Rivshin <DRivshin@allworx.com> | |
7 | ||
8 | commit 83977443938122baeed28dc9f078db3da9855f7c upstream. | |
9 | ||
10 | omap_gpio_debounce() does not validate that the requested debounce | |
11 | is within a range it can handle. Instead it lets the register value | |
12 | wrap silently, and always returns success. | |
13 | ||
14 | This can lead to all sorts of unexpected behavior, such as gpio_keys | |
15 | asking for a too-long debounce, but getting a very short debounce in | |
16 | practice. | |
17 | ||
18 | Fix this by returning -EINVAL if the requested value does not fit into | |
19 | the register field. If there is no debounce clock available at all, | |
20 | return -ENOTSUPP. | |
21 | ||
22 | Fixes: e85ec6c3047b ("gpio: omap: fix omap2_set_gpio_debounce") | |
23 | Signed-off-by: David Rivshin <drivshin@allworx.com> | |
24 | Acked-by: Grygorii Strashko <grygorii.strashko@ti.com> | |
25 | Signed-off-by: Linus Walleij <linus.walleij@linaro.org> | |
26 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
27 | ||
28 | --- | |
29 | drivers/gpio/gpio-omap.c | 23 +++++++++++++++++------ | |
30 | 1 file changed, 17 insertions(+), 6 deletions(-) | |
31 | ||
32 | --- a/drivers/gpio/gpio-omap.c | |
33 | +++ b/drivers/gpio/gpio-omap.c | |
34 | @@ -208,9 +208,11 @@ static inline void omap_gpio_dbck_disabl | |
35 | * OMAP's debounce time is in 31us steps | |
36 | * <debounce time> = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 | |
37 | * so we need to convert and round up to the closest unit. | |
38 | + * | |
39 | + * Return: 0 on success, negative error otherwise. | |
40 | */ | |
41 | -static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, | |
42 | - unsigned debounce) | |
43 | +static int omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, | |
44 | + unsigned debounce) | |
45 | { | |
46 | void __iomem *reg; | |
47 | u32 val; | |
48 | @@ -218,11 +220,12 @@ static void omap2_set_gpio_debounce(stru | |
49 | bool enable = !!debounce; | |
50 | ||
51 | if (!bank->dbck_flag) | |
52 | - return; | |
53 | + return -ENOTSUPP; | |
54 | ||
55 | if (enable) { | |
56 | debounce = DIV_ROUND_UP(debounce, 31) - 1; | |
57 | - debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; | |
58 | + if ((debounce & OMAP4_GPIO_DEBOUNCINGTIME_MASK) != debounce) | |
59 | + return -EINVAL; | |
60 | } | |
61 | ||
62 | l = BIT(offset); | |
63 | @@ -255,6 +258,8 @@ static void omap2_set_gpio_debounce(stru | |
64 | bank->context.debounce = debounce; | |
65 | bank->context.debounce_en = val; | |
66 | } | |
67 | + | |
68 | + return 0; | |
69 | } | |
70 | ||
71 | /** | |
72 | @@ -964,14 +969,20 @@ static int omap_gpio_debounce(struct gpi | |
73 | { | |
74 | struct gpio_bank *bank; | |
75 | unsigned long flags; | |
76 | + int ret; | |
77 | ||
78 | bank = gpiochip_get_data(chip); | |
79 | ||
80 | raw_spin_lock_irqsave(&bank->lock, flags); | |
81 | - omap2_set_gpio_debounce(bank, offset, debounce); | |
82 | + ret = omap2_set_gpio_debounce(bank, offset, debounce); | |
83 | raw_spin_unlock_irqrestore(&bank->lock, flags); | |
84 | ||
85 | - return 0; | |
86 | + if (ret) | |
87 | + dev_info(chip->parent, | |
88 | + "Could not set line %u debounce to %u microseconds (%d)", | |
89 | + offset, debounce, ret); | |
90 | + | |
91 | + return ret; | |
92 | } | |
93 | ||
94 | static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |