diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2016-04-25 06:38:34 -0400 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2016-04-29 05:03:15 -0400 |
commit | 3737de42afb8d76f405689a4699e8e5dd5e2ef96 (patch) | |
tree | 543f4edbaea901b4ac4f4ad2d7b8baccbf5006ce /drivers/gpio | |
parent | b546be0db955840e2c14aae5d8e5f93a456f9982 (diff) |
gpio: tegra: Add support for gpio debounce
NVIDIA's Tegra210 support the HW debounce in the GPIO controller
for all its GPIO pins.
Add support for setting debounce timing by implementing the
set_debounce callback of gpiochip.
Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-tegra.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 653825db4baa..b3ddd922290d 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c | |||
@@ -46,10 +46,13 @@ | |||
46 | #define GPIO_INT_ENB(t, x) (GPIO_REG(t, x) + 0x50) | 46 | #define GPIO_INT_ENB(t, x) (GPIO_REG(t, x) + 0x50) |
47 | #define GPIO_INT_LVL(t, x) (GPIO_REG(t, x) + 0x60) | 47 | #define GPIO_INT_LVL(t, x) (GPIO_REG(t, x) + 0x60) |
48 | #define GPIO_INT_CLR(t, x) (GPIO_REG(t, x) + 0x70) | 48 | #define GPIO_INT_CLR(t, x) (GPIO_REG(t, x) + 0x70) |
49 | #define GPIO_DBC_CNT(t, x) (GPIO_REG(t, x) + 0xF0) | ||
50 | |||
49 | 51 | ||
50 | #define GPIO_MSK_CNF(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x00) | 52 | #define GPIO_MSK_CNF(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x00) |
51 | #define GPIO_MSK_OE(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x10) | 53 | #define GPIO_MSK_OE(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x10) |
52 | #define GPIO_MSK_OUT(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0X20) | 54 | #define GPIO_MSK_OUT(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0X20) |
55 | #define GPIO_MSK_DBC_EN(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x30) | ||
53 | #define GPIO_MSK_INT_STA(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x40) | 56 | #define GPIO_MSK_INT_STA(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x40) |
54 | #define GPIO_MSK_INT_ENB(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x50) | 57 | #define GPIO_MSK_INT_ENB(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x50) |
55 | #define GPIO_MSK_INT_LVL(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x60) | 58 | #define GPIO_MSK_INT_LVL(t, x) (GPIO_REG(t, x) + t->soc->upper_offset + 0x60) |
@@ -67,6 +70,7 @@ struct tegra_gpio_bank { | |||
67 | int bank; | 70 | int bank; |
68 | int irq; | 71 | int irq; |
69 | spinlock_t lvl_lock[4]; | 72 | spinlock_t lvl_lock[4]; |
73 | spinlock_t dbc_lock[4]; /* Lock for updating debounce count register */ | ||
70 | #ifdef CONFIG_PM_SLEEP | 74 | #ifdef CONFIG_PM_SLEEP |
71 | u32 cnf[4]; | 75 | u32 cnf[4]; |
72 | u32 out[4]; | 76 | u32 out[4]; |
@@ -74,11 +78,14 @@ struct tegra_gpio_bank { | |||
74 | u32 int_enb[4]; | 78 | u32 int_enb[4]; |
75 | u32 int_lvl[4]; | 79 | u32 int_lvl[4]; |
76 | u32 wake_enb[4]; | 80 | u32 wake_enb[4]; |
81 | u32 dbc_enb[4]; | ||
77 | #endif | 82 | #endif |
83 | u32 dbc_cnt[4]; | ||
78 | struct tegra_gpio_info *tgi; | 84 | struct tegra_gpio_info *tgi; |
79 | }; | 85 | }; |
80 | 86 | ||
81 | struct tegra_gpio_soc_config { | 87 | struct tegra_gpio_soc_config { |
88 | bool debounce_supported; | ||
82 | u32 bank_stride; | 89 | u32 bank_stride; |
83 | u32 upper_offset; | 90 | u32 upper_offset; |
84 | }; | 91 | }; |
@@ -184,6 +191,39 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | |||
184 | return 0; | 191 | return 0; |
185 | } | 192 | } |
186 | 193 | ||
194 | static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset, | ||
195 | unsigned int debounce) | ||
196 | { | ||
197 | struct tegra_gpio_info *tgi = gpiochip_get_data(chip); | ||
198 | struct tegra_gpio_bank *bank = &tgi->bank_info[GPIO_BANK(offset)]; | ||
199 | unsigned int debounce_ms = DIV_ROUND_UP(debounce, 1000); | ||
200 | unsigned long flags; | ||
201 | int port; | ||
202 | |||
203 | if (!debounce_ms) { | ||
204 | tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), | ||
205 | offset, 0); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | debounce_ms = min(debounce_ms, 255U); | ||
210 | port = GPIO_PORT(offset); | ||
211 | |||
212 | /* There is only one debounce count register per port and hence | ||
213 | * set the maximum of current and requested debounce time. | ||
214 | */ | ||
215 | spin_lock_irqsave(&bank->dbc_lock[port], flags); | ||
216 | if (bank->dbc_cnt[port] < debounce_ms) { | ||
217 | tegra_gpio_writel(tgi, debounce_ms, GPIO_DBC_CNT(tgi, offset)); | ||
218 | bank->dbc_cnt[port] = debounce_ms; | ||
219 | } | ||
220 | spin_unlock_irqrestore(&bank->dbc_lock[port], flags); | ||
221 | |||
222 | tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), offset, 1); | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
187 | static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) | 227 | static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset) |
188 | { | 228 | { |
189 | struct tegra_gpio_info *tgi = gpiochip_get_data(chip); | 229 | struct tegra_gpio_info *tgi = gpiochip_get_data(chip); |
@@ -350,6 +390,14 @@ static int tegra_gpio_resume(struct device *dev) | |||
350 | unsigned int gpio = (b<<5) | (p<<3); | 390 | unsigned int gpio = (b<<5) | (p<<3); |
351 | tegra_gpio_writel(tgi, bank->cnf[p], | 391 | tegra_gpio_writel(tgi, bank->cnf[p], |
352 | GPIO_CNF(tgi, gpio)); | 392 | GPIO_CNF(tgi, gpio)); |
393 | |||
394 | if (tgi->soc->debounce_supported) { | ||
395 | tegra_gpio_writel(tgi, bank->dbc_cnt[p], | ||
396 | GPIO_DBC_CNT(tgi, gpio)); | ||
397 | tegra_gpio_writel(tgi, bank->dbc_enb[p], | ||
398 | GPIO_MSK_DBC_EN(tgi, gpio)); | ||
399 | } | ||
400 | |||
353 | tegra_gpio_writel(tgi, bank->out[p], | 401 | tegra_gpio_writel(tgi, bank->out[p], |
354 | GPIO_OUT(tgi, gpio)); | 402 | GPIO_OUT(tgi, gpio)); |
355 | tegra_gpio_writel(tgi, bank->oe[p], | 403 | tegra_gpio_writel(tgi, bank->oe[p], |
@@ -385,6 +433,13 @@ static int tegra_gpio_suspend(struct device *dev) | |||
385 | GPIO_OUT(tgi, gpio)); | 433 | GPIO_OUT(tgi, gpio)); |
386 | bank->oe[p] = tegra_gpio_readl(tgi, | 434 | bank->oe[p] = tegra_gpio_readl(tgi, |
387 | GPIO_OE(tgi, gpio)); | 435 | GPIO_OE(tgi, gpio)); |
436 | if (tgi->soc->debounce_supported) { | ||
437 | bank->dbc_enb[p] = tegra_gpio_readl(tgi, | ||
438 | GPIO_MSK_DBC_EN(tgi, gpio)); | ||
439 | bank->dbc_enb[p] = (bank->dbc_enb[p] << 8) | | ||
440 | bank->dbc_enb[p]; | ||
441 | } | ||
442 | |||
388 | bank->int_enb[p] = tegra_gpio_readl(tgi, | 443 | bank->int_enb[p] = tegra_gpio_readl(tgi, |
389 | GPIO_INT_ENB(tgi, gpio)); | 444 | GPIO_INT_ENB(tgi, gpio)); |
390 | bank->int_lvl[p] = tegra_gpio_readl(tgi, | 445 | bank->int_lvl[p] = tegra_gpio_readl(tgi, |
@@ -538,6 +593,9 @@ static int tegra_gpio_probe(struct platform_device *pdev) | |||
538 | 593 | ||
539 | platform_set_drvdata(pdev, tgi); | 594 | platform_set_drvdata(pdev, tgi); |
540 | 595 | ||
596 | if (config->debounce_supported) | ||
597 | tgi->gc.set_debounce = tegra_gpio_set_debounce; | ||
598 | |||
541 | tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count * | 599 | tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count * |
542 | sizeof(*tgi->bank_info), GFP_KERNEL); | 600 | sizeof(*tgi->bank_info), GFP_KERNEL); |
543 | if (!tgi->bank_info) | 601 | if (!tgi->bank_info) |
@@ -597,8 +655,10 @@ static int tegra_gpio_probe(struct platform_device *pdev) | |||
597 | irq_set_chained_handler_and_data(bank->irq, | 655 | irq_set_chained_handler_and_data(bank->irq, |
598 | tegra_gpio_irq_handler, bank); | 656 | tegra_gpio_irq_handler, bank); |
599 | 657 | ||
600 | for (j = 0; j < 4; j++) | 658 | for (j = 0; j < 4; j++) { |
601 | spin_lock_init(&bank->lvl_lock[j]); | 659 | spin_lock_init(&bank->lvl_lock[j]); |
660 | spin_lock_init(&bank->dbc_lock[j]); | ||
661 | } | ||
602 | } | 662 | } |
603 | 663 | ||
604 | tegra_gpio_debuginit(tgi); | 664 | tegra_gpio_debuginit(tgi); |
@@ -616,7 +676,14 @@ static const struct tegra_gpio_soc_config tegra30_gpio_config = { | |||
616 | .upper_offset = 0x80, | 676 | .upper_offset = 0x80, |
617 | }; | 677 | }; |
618 | 678 | ||
679 | static const struct tegra_gpio_soc_config tegra210_gpio_config = { | ||
680 | .debounce_supported = true, | ||
681 | .bank_stride = 0x100, | ||
682 | .upper_offset = 0x80, | ||
683 | }; | ||
684 | |||
619 | static const struct of_device_id tegra_gpio_of_match[] = { | 685 | static const struct of_device_id tegra_gpio_of_match[] = { |
686 | { .compatible = "nvidia,tegra210-gpio", .data = &tegra210_gpio_config }, | ||
620 | { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, | 687 | { .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config }, |
621 | { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, | 688 | { .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config }, |
622 | { }, | 689 | { }, |