linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
@ 2016-04-25 10:38 Laxman Dewangan
  2016-04-25 10:38 ` [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data() Laxman Dewangan
                   ` (4 more replies)
  0 siblings, 5 replies; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-25 10:38 UTC (permalink / raw)
  To: swarren, linus.walleij, gnurou, thierry.reding, linux-gpio,
	linux-tegra, linux-kernel
  Cc: Laxman Dewangan

Add support for the debounce as Tegra210 support debounce in HW.
Also do the clenaups to remove all global variables.

Changes from V3:
- Rearranging debounce registers and lock the DB CNT registers.
Changes from V4:
- Get rid of tegra_gpio_chip and tegra_irq_chip as global.

Laxman Dewangan (4):
  gpio: tegra: Don't open code of_device_get_match_data()
  gpio: tegra: Make of_device_id compatible data to constant
  gpio: tegra: Get rid of all file scoped global variables
  gpio: tegra: Add support for gpio debounce

 drivers/gpio/gpio-tegra.c | 407 +++++++++++++++++++++++++++++-----------------
 1 file changed, 261 insertions(+), 146 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data()
  2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
@ 2016-04-25 10:38 ` Laxman Dewangan
  2016-04-29  8:59   ` Linus Walleij
  2016-04-25 10:38 ` [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant Laxman Dewangan
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-25 10:38 UTC (permalink / raw)
  To: swarren, linus.walleij, gnurou, thierry.reding, linux-gpio,
	linux-tegra, linux-kernel
  Cc: Laxman Dewangan

Use of_device_get_match_data() for getting matched data
instead of implementing this locally.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
Acked-by: Thierry Reding <treding@nvidia.com>

---
Collected reviewed/ack by from Stephen, Alexandre and Thieery.
---
 drivers/gpio/gpio-tegra.c | 50 +++++++++++++++++++++++------------------------
 1 file changed, 24 insertions(+), 26 deletions(-)

diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 790bb11..1b0c497 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -75,6 +75,11 @@ struct tegra_gpio_bank {
 #endif
 };
 
+struct tegra_gpio_soc_config {
+	u32 bank_stride;
+	u32 upper_offset;
+};
+
 static struct device *dev;
 static struct irq_domain *irq_domain;
 static void __iomem *regs;
@@ -445,27 +450,6 @@ static const struct dev_pm_ops tegra_gpio_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
 };
 
-struct tegra_gpio_soc_config {
-	u32 bank_stride;
-	u32 upper_offset;
-};
-
-static struct tegra_gpio_soc_config tegra20_gpio_config = {
-	.bank_stride = 0x80,
-	.upper_offset = 0x800,
-};
-
-static struct tegra_gpio_soc_config tegra30_gpio_config = {
-	.bank_stride = 0x100,
-	.upper_offset = 0x80,
-};
-
-static const struct of_device_id tegra_gpio_of_match[] = {
-	{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
-	{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
-	{ },
-};
-
 /* This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
  */
@@ -473,8 +457,7 @@ static struct lock_class_key gpio_lock_class;
 
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
-	const struct of_device_id *match;
-	struct tegra_gpio_soc_config *config;
+	const struct tegra_gpio_soc_config *config;
 	struct resource *res;
 	struct tegra_gpio_bank *bank;
 	int ret;
@@ -484,12 +467,11 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
 	dev = &pdev->dev;
 
-	match = of_match_device(tegra_gpio_of_match, &pdev->dev);
-	if (!match) {
+	config = of_device_get_match_data(&pdev->dev);
+	if (!config) {
 		dev_err(&pdev->dev, "Error: No device match found\n");
 		return -ENODEV;
 	}
-	config = (struct tegra_gpio_soc_config *)match->data;
 
 	tegra_gpio_bank_stride = config->bank_stride;
 	tegra_gpio_upper_offset = config->upper_offset;
@@ -578,6 +560,22 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	return 0;
 }
 
+static struct tegra_gpio_soc_config tegra20_gpio_config = {
+	.bank_stride = 0x80,
+	.upper_offset = 0x800,
+};
+
+static struct tegra_gpio_soc_config tegra30_gpio_config = {
+	.bank_stride = 0x100,
+	.upper_offset = 0x80,
+};
+
+static const struct of_device_id tegra_gpio_of_match[] = {
+	{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
+	{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
+	{ },
+};
+
 static struct platform_driver tegra_gpio_driver = {
 	.driver		= {
 		.name	= "tegra-gpio",
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant
  2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
  2016-04-25 10:38 ` [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data() Laxman Dewangan
@ 2016-04-25 10:38 ` Laxman Dewangan
  2016-04-29  9:00   ` Linus Walleij
  2016-04-25 10:38 ` [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables Laxman Dewangan
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-25 10:38 UTC (permalink / raw)
  To: swarren, linus.walleij, gnurou, thierry.reding, linux-gpio,
	linux-tegra, linux-kernel
  Cc: Laxman Dewangan

The data member of the of_device_id is the constant type
and hence all static structure which is used for this
initialisation as static.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Suggested-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>

---
Changes from V2:
-This is new in series based on discussion on previous patches.

Changes from V3:
- Collected RB of Stephen.
---
 drivers/gpio/gpio-tegra.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 1b0c497..cd69422 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -560,12 +560,12 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	return 0;
 }
 
-static struct tegra_gpio_soc_config tegra20_gpio_config = {
+static const struct tegra_gpio_soc_config tegra20_gpio_config = {
 	.bank_stride = 0x80,
 	.upper_offset = 0x800,
 };
 
-static struct tegra_gpio_soc_config tegra30_gpio_config = {
+static const struct tegra_gpio_soc_config tegra30_gpio_config = {
 	.bank_stride = 0x100,
 	.upper_offset = 0x80,
 };
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables
  2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
  2016-04-25 10:38 ` [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data() Laxman Dewangan
  2016-04-25 10:38 ` [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant Laxman Dewangan
@ 2016-04-25 10:38 ` Laxman Dewangan
  2016-04-29  9:01   ` Linus Walleij
  2016-04-25 10:38 ` [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce Laxman Dewangan
  2016-04-29  9:07 ` [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Linus Walleij
  4 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-25 10:38 UTC (permalink / raw)
  To: swarren, linus.walleij, gnurou, thierry.reding, linux-gpio,
	linux-tegra, linux-kernel
  Cc: Laxman Dewangan

Move the file scoped multiple global variable from Tegra GPIO
driver to the structure and make this as gpiochip data which
can be referred from GPIO chip callbacks.

Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>

---
This patch is reworked on top of earlier patch
gpio: tegra: Remove the need of keeping device handle for gpio driver

There was review comment that we should get for all variable and hence
this is outcome of the discussion.

Changes from V3:
- Remove DBC/EN registers.
- Remove non-required new lines.
- Collected RB from Stephen.

Changes from V4:
- Make gpio_chip gc as instance instead of pointer in tegra_gpio_info and
 get rid of tegra_gpio_info.
- Add irq_chip instance in tegra_gpio_info and get rid of tegra_irq_chip.
- get rid of gpio_class_lock.
- Collected RB from Alexandre
---
 drivers/gpio/gpio-tegra.c | 350 ++++++++++++++++++++++++++--------------------
 1 file changed, 198 insertions(+), 152 deletions(-)

diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index cd69422..653825d 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -35,24 +35,24 @@
 #define GPIO_PORT(x)		(((x) >> 3) & 0x3)
 #define GPIO_BIT(x)		((x) & 0x7)
 
-#define GPIO_REG(x)		(GPIO_BANK(x) * tegra_gpio_bank_stride + \
+#define GPIO_REG(tgi, x)	(GPIO_BANK(x) * tgi->soc->bank_stride + \
 					GPIO_PORT(x) * 4)
 
-#define GPIO_CNF(x)		(GPIO_REG(x) + 0x00)
-#define GPIO_OE(x)		(GPIO_REG(x) + 0x10)
-#define GPIO_OUT(x)		(GPIO_REG(x) + 0X20)
-#define GPIO_IN(x)		(GPIO_REG(x) + 0x30)
-#define GPIO_INT_STA(x)		(GPIO_REG(x) + 0x40)
-#define GPIO_INT_ENB(x)		(GPIO_REG(x) + 0x50)
-#define GPIO_INT_LVL(x)		(GPIO_REG(x) + 0x60)
-#define GPIO_INT_CLR(x)		(GPIO_REG(x) + 0x70)
-
-#define GPIO_MSK_CNF(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0x00)
-#define GPIO_MSK_OE(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0x10)
-#define GPIO_MSK_OUT(x)		(GPIO_REG(x) + tegra_gpio_upper_offset + 0X20)
-#define GPIO_MSK_INT_STA(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x40)
-#define GPIO_MSK_INT_ENB(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x50)
-#define GPIO_MSK_INT_LVL(x)	(GPIO_REG(x) + tegra_gpio_upper_offset + 0x60)
+#define GPIO_CNF(t, x)		(GPIO_REG(t, x) + 0x00)
+#define GPIO_OE(t, x)		(GPIO_REG(t, x) + 0x10)
+#define GPIO_OUT(t, x)		(GPIO_REG(t, x) + 0X20)
+#define GPIO_IN(t, x)		(GPIO_REG(t, x) + 0x30)
+#define GPIO_INT_STA(t, x)	(GPIO_REG(t, x) + 0x40)
+#define GPIO_INT_ENB(t, x)	(GPIO_REG(t, x) + 0x50)
+#define GPIO_INT_LVL(t, x)	(GPIO_REG(t, x) + 0x60)
+#define GPIO_INT_CLR(t, x)	(GPIO_REG(t, x) + 0x70)
+
+#define GPIO_MSK_CNF(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x00)
+#define GPIO_MSK_OE(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x10)
+#define GPIO_MSK_OUT(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0X20)
+#define GPIO_MSK_INT_STA(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x40)
+#define GPIO_MSK_INT_ENB(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x50)
+#define GPIO_MSK_INT_LVL(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x60)
 
 #define GPIO_INT_LVL_MASK		0x010101
 #define GPIO_INT_LVL_EDGE_RISING	0x000101
@@ -61,6 +61,8 @@
 #define GPIO_INT_LVL_LEVEL_HIGH		0x000001
 #define GPIO_INT_LVL_LEVEL_LOW		0x000000
 
+struct tegra_gpio_info;
+
 struct tegra_gpio_bank {
 	int bank;
 	int irq;
@@ -73,6 +75,7 @@ struct tegra_gpio_bank {
 	u32 int_lvl[4];
 	u32 wake_enb[4];
 #endif
+	struct tegra_gpio_info *tgi;
 };
 
 struct tegra_gpio_soc_config {
@@ -80,22 +83,27 @@ struct tegra_gpio_soc_config {
 	u32 upper_offset;
 };
 
-static struct device *dev;
-static struct irq_domain *irq_domain;
-static void __iomem *regs;
-static u32 tegra_gpio_bank_count;
-static u32 tegra_gpio_bank_stride;
-static u32 tegra_gpio_upper_offset;
-static struct tegra_gpio_bank *tegra_gpio_banks;
+struct tegra_gpio_info {
+	struct device				*dev;
+	void __iomem				*regs;
+	struct irq_domain			*irq_domain;
+	struct tegra_gpio_bank			*bank_info;
+	const struct tegra_gpio_soc_config	*soc;
+	struct gpio_chip			gc;
+	struct irq_chip				ic;
+	struct lock_class_key			lock_class;
+	u32					bank_count;
+};
 
-static inline void tegra_gpio_writel(u32 val, u32 reg)
+static inline void tegra_gpio_writel(struct tegra_gpio_info *tgi,
+				     u32 val, u32 reg)
 {
-	__raw_writel(val, regs + reg);
+	__raw_writel(val, tgi->regs + reg);
 }
 
-static inline u32 tegra_gpio_readl(u32 reg)
+static inline u32 tegra_gpio_readl(struct tegra_gpio_info *tgi, u32 reg)
 {
-	return __raw_readl(regs + reg);
+	return __raw_readl(tgi->regs + reg);
 }
 
 static int tegra_gpio_compose(int bank, int port, int bit)
@@ -103,24 +111,25 @@ static int tegra_gpio_compose(int bank, int port, int bit)
 	return (bank << 5) | ((port & 0x3) << 3) | (bit & 0x7);
 }
 
-static void tegra_gpio_mask_write(u32 reg, int gpio, int value)
+static void tegra_gpio_mask_write(struct tegra_gpio_info *tgi, u32 reg,
+				  int gpio, int value)
 {
 	u32 val;
 
 	val = 0x100 << GPIO_BIT(gpio);
 	if (value)
 		val |= 1 << GPIO_BIT(gpio);
-	tegra_gpio_writel(val, reg);
+	tegra_gpio_writel(tgi, val, reg);
 }
 
-static void tegra_gpio_enable(int gpio)
+static void tegra_gpio_enable(struct tegra_gpio_info *tgi, int gpio)
 {
-	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 1);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 1);
 }
 
-static void tegra_gpio_disable(int gpio)
+static void tegra_gpio_disable(struct tegra_gpio_info *tgi, int gpio)
 {
-	tegra_gpio_mask_write(GPIO_MSK_CNF(gpio), gpio, 0);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_CNF(tgi, gpio), gpio, 0);
 }
 
 static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
@@ -130,83 +139,90 @@ static int tegra_gpio_request(struct gpio_chip *chip, unsigned offset)
 
 static void tegra_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
 	pinctrl_free_gpio(offset);
-	tegra_gpio_disable(offset);
+	tegra_gpio_disable(tgi, offset);
 }
 
 static void tegra_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
-	tegra_gpio_mask_write(GPIO_MSK_OUT(offset), offset, value);
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+	tegra_gpio_mask_write(tgi, GPIO_MSK_OUT(tgi, offset), offset, value);
 }
 
 static int tegra_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+	int bval = BIT(GPIO_BIT(offset));
+
 	/* If gpio is in output mode then read from the out value */
-	if ((tegra_gpio_readl(GPIO_OE(offset)) >> GPIO_BIT(offset)) & 1)
-		return (tegra_gpio_readl(GPIO_OUT(offset)) >>
-				GPIO_BIT(offset)) & 0x1;
+	if (tegra_gpio_readl(tgi, GPIO_OE(tgi, offset)) & bval)
+		return !!(tegra_gpio_readl(tgi, GPIO_OUT(tgi, offset)) & bval);
 
-	return (tegra_gpio_readl(GPIO_IN(offset)) >> GPIO_BIT(offset)) & 0x1;
+	return !!(tegra_gpio_readl(tgi, GPIO_IN(tgi, offset)) & bval);
 }
 
 static int tegra_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
-	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 0);
-	tegra_gpio_enable(offset);
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
+	tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 0);
+	tegra_gpio_enable(tgi, offset);
 	return 0;
 }
 
 static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 					int value)
 {
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+
 	tegra_gpio_set(chip, offset, value);
-	tegra_gpio_mask_write(GPIO_MSK_OE(offset), offset, 1);
-	tegra_gpio_enable(offset);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, offset), offset, 1);
+	tegra_gpio_enable(tgi, offset);
 	return 0;
 }
 
 static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	return irq_find_mapping(irq_domain, offset);
-}
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
 
-static struct gpio_chip tegra_gpio_chip = {
-	.label			= "tegra-gpio",
-	.request		= tegra_gpio_request,
-	.free			= tegra_gpio_free,
-	.direction_input	= tegra_gpio_direction_input,
-	.get			= tegra_gpio_get,
-	.direction_output	= tegra_gpio_direction_output,
-	.set			= tegra_gpio_set,
-	.to_irq			= tegra_gpio_to_irq,
-	.base			= 0,
-};
+	return irq_find_mapping(tgi->irq_domain, offset);
+}
 
 static void tegra_gpio_irq_ack(struct irq_data *d)
 {
+	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = bank->tgi;
 	int gpio = d->hwirq;
 
-	tegra_gpio_writel(1 << GPIO_BIT(gpio), GPIO_INT_CLR(gpio));
+	tegra_gpio_writel(tgi, 1 << GPIO_BIT(gpio), GPIO_INT_CLR(tgi, gpio));
 }
 
 static void tegra_gpio_irq_mask(struct irq_data *d)
 {
+	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = bank->tgi;
 	int gpio = d->hwirq;
 
-	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 0);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 0);
 }
 
 static void tegra_gpio_irq_unmask(struct irq_data *d)
 {
+	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = bank->tgi;
 	int gpio = d->hwirq;
 
-	tegra_gpio_mask_write(GPIO_MSK_INT_ENB(gpio), gpio, 1);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_INT_ENB(tgi, gpio), gpio, 1);
 }
 
 static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 {
 	int gpio = d->hwirq;
 	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = bank->tgi;
 	int port = GPIO_PORT(gpio);
 	int lvl_type;
 	int val;
@@ -238,23 +254,24 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 		return -EINVAL;
 	}
 
-	ret = gpiochip_lock_as_irq(&tegra_gpio_chip, gpio);
+	ret = gpiochip_lock_as_irq(&tgi->gc, gpio);
 	if (ret) {
-		dev_err(dev, "unable to lock Tegra GPIO %d as IRQ\n", gpio);
+		dev_err(tgi->dev,
+			"unable to lock Tegra GPIO %d as IRQ\n", gpio);
 		return ret;
 	}
 
 	spin_lock_irqsave(&bank->lvl_lock[port], flags);
 
-	val = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+	val = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
 	val &= ~(GPIO_INT_LVL_MASK << GPIO_BIT(gpio));
 	val |= lvl_type << GPIO_BIT(gpio);
-	tegra_gpio_writel(val, GPIO_INT_LVL(gpio));
+	tegra_gpio_writel(tgi, val, GPIO_INT_LVL(tgi, gpio));
 
 	spin_unlock_irqrestore(&bank->lvl_lock[port], flags);
 
-	tegra_gpio_mask_write(GPIO_MSK_OE(gpio), gpio, 0);
-	tegra_gpio_enable(gpio);
+	tegra_gpio_mask_write(tgi, GPIO_MSK_OE(tgi, gpio), gpio, 0);
+	tegra_gpio_enable(tgi, gpio);
 
 	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
 		irq_set_handler_locked(d, handle_level_irq);
@@ -266,9 +283,11 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type)
 
 static void tegra_gpio_irq_shutdown(struct irq_data *d)
 {
+	struct tegra_gpio_bank *bank = irq_data_get_irq_chip_data(d);
+	struct tegra_gpio_info *tgi = bank->tgi;
 	int gpio = d->hwirq;
 
-	gpiochip_unlock_as_irq(&tegra_gpio_chip, gpio);
+	gpiochip_unlock_as_irq(&tgi->gc, gpio);
 }
 
 static void tegra_gpio_irq_handler(struct irq_desc *desc)
@@ -276,19 +295,24 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
 	int port;
 	int pin;
 	int unmasked = 0;
+	int gpio;
+	u32 lvl;
+	unsigned long sta;
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc);
+	struct tegra_gpio_info *tgi = bank->tgi;
 
 	chained_irq_enter(chip, desc);
 
 	for (port = 0; port < 4; port++) {
-		int gpio = tegra_gpio_compose(bank->bank, port, 0);
-		unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) &
-			tegra_gpio_readl(GPIO_INT_ENB(gpio));
-		u32 lvl = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+		gpio = tegra_gpio_compose(bank->bank, port, 0);
+		sta = tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)) &
+			tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio));
+		lvl = tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio));
 
 		for_each_set_bit(pin, &sta, 8) {
-			tegra_gpio_writel(1 << pin, GPIO_INT_CLR(gpio));
+			tegra_gpio_writel(tgi, 1 << pin,
+					  GPIO_INT_CLR(tgi, gpio));
 
 			/* if gpio is edge triggered, clear condition
 			 * before executing the handler so that we don't
@@ -311,22 +335,29 @@ static void tegra_gpio_irq_handler(struct irq_desc *desc)
 #ifdef CONFIG_PM_SLEEP
 static int tegra_gpio_resume(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
 	unsigned long flags;
 	int b;
 	int p;
 
 	local_irq_save(flags);
 
-	for (b = 0; b < tegra_gpio_bank_count; b++) {
-		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+	for (b = 0; b < tgi->bank_count; b++) {
+		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
 			unsigned int gpio = (b<<5) | (p<<3);
-			tegra_gpio_writel(bank->cnf[p], GPIO_CNF(gpio));
-			tegra_gpio_writel(bank->out[p], GPIO_OUT(gpio));
-			tegra_gpio_writel(bank->oe[p], GPIO_OE(gpio));
-			tegra_gpio_writel(bank->int_lvl[p], GPIO_INT_LVL(gpio));
-			tegra_gpio_writel(bank->int_enb[p], GPIO_INT_ENB(gpio));
+			tegra_gpio_writel(tgi, bank->cnf[p],
+					  GPIO_CNF(tgi, gpio));
+			tegra_gpio_writel(tgi, bank->out[p],
+					  GPIO_OUT(tgi, gpio));
+			tegra_gpio_writel(tgi, bank->oe[p],
+					  GPIO_OE(tgi, gpio));
+			tegra_gpio_writel(tgi, bank->int_lvl[p],
+					  GPIO_INT_LVL(tgi, gpio));
+			tegra_gpio_writel(tgi, bank->int_enb[p],
+					  GPIO_INT_ENB(tgi, gpio));
 		}
 	}
 
@@ -336,25 +367,32 @@ static int tegra_gpio_resume(struct device *dev)
 
 static int tegra_gpio_suspend(struct device *dev)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct tegra_gpio_info *tgi = platform_get_drvdata(pdev);
 	unsigned long flags;
 	int b;
 	int p;
 
 	local_irq_save(flags);
-	for (b = 0; b < tegra_gpio_bank_count; b++) {
-		struct tegra_gpio_bank *bank = &tegra_gpio_banks[b];
+	for (b = 0; b < tgi->bank_count; b++) {
+		struct tegra_gpio_bank *bank = &tgi->bank_info[b];
 
 		for (p = 0; p < ARRAY_SIZE(bank->oe); p++) {
 			unsigned int gpio = (b<<5) | (p<<3);
-			bank->cnf[p] = tegra_gpio_readl(GPIO_CNF(gpio));
-			bank->out[p] = tegra_gpio_readl(GPIO_OUT(gpio));
-			bank->oe[p] = tegra_gpio_readl(GPIO_OE(gpio));
-			bank->int_enb[p] = tegra_gpio_readl(GPIO_INT_ENB(gpio));
-			bank->int_lvl[p] = tegra_gpio_readl(GPIO_INT_LVL(gpio));
+			bank->cnf[p] = tegra_gpio_readl(tgi,
+							GPIO_CNF(tgi, gpio));
+			bank->out[p] = tegra_gpio_readl(tgi,
+							GPIO_OUT(tgi, gpio));
+			bank->oe[p] = tegra_gpio_readl(tgi,
+						       GPIO_OE(tgi, gpio));
+			bank->int_enb[p] = tegra_gpio_readl(tgi,
+						GPIO_INT_ENB(tgi, gpio));
+			bank->int_lvl[p] = tegra_gpio_readl(tgi,
+						GPIO_INT_LVL(tgi, gpio));
 
 			/* Enable gpio irq for wake up source */
-			tegra_gpio_writel(bank->wake_enb[p],
-					  GPIO_INT_ENB(gpio));
+			tegra_gpio_writel(tgi, bank->wake_enb[p],
+					  GPIO_INT_ENB(tgi, gpio));
 		}
 	}
 	local_irq_restore(flags);
@@ -387,22 +425,23 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
 
 static int dbg_gpio_show(struct seq_file *s, void *unused)
 {
+	struct tegra_gpio_info *tgi = s->private;
 	int i;
 	int j;
 
-	for (i = 0; i < tegra_gpio_bank_count; i++) {
+	for (i = 0; i < tgi->bank_count; i++) {
 		for (j = 0; j < 4; j++) {
 			int gpio = tegra_gpio_compose(i, j, 0);
 			seq_printf(s,
 				"%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
 				i, j,
-				tegra_gpio_readl(GPIO_CNF(gpio)),
-				tegra_gpio_readl(GPIO_OE(gpio)),
-				tegra_gpio_readl(GPIO_OUT(gpio)),
-				tegra_gpio_readl(GPIO_IN(gpio)),
-				tegra_gpio_readl(GPIO_INT_STA(gpio)),
-				tegra_gpio_readl(GPIO_INT_ENB(gpio)),
-				tegra_gpio_readl(GPIO_INT_LVL(gpio)));
+				tegra_gpio_readl(tgi, GPIO_CNF(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_OE(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_OUT(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_IN(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_INT_STA(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_INT_ENB(tgi, gpio)),
+				tegra_gpio_readl(tgi, GPIO_INT_LVL(tgi, gpio)));
 		}
 	}
 	return 0;
@@ -410,7 +449,7 @@ static int dbg_gpio_show(struct seq_file *s, void *unused)
 
 static int dbg_gpio_open(struct inode *inode, struct file *file)
 {
-	return single_open(file, dbg_gpio_show, &inode->i_private);
+	return single_open(file, dbg_gpio_show, inode->i_private);
 }
 
 static const struct file_operations debug_fops = {
@@ -420,44 +459,28 @@ static const struct file_operations debug_fops = {
 	.release	= single_release,
 };
 
-static void tegra_gpio_debuginit(void)
+static void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
 {
 	(void) debugfs_create_file("tegra_gpio", S_IRUGO,
-					NULL, NULL, &debug_fops);
+					NULL, tgi, &debug_fops);
 }
 
 #else
 
-static inline void tegra_gpio_debuginit(void)
+static inline void tegra_gpio_debuginit(struct tegra_gpio_info *tgi)
 {
 }
 
 #endif
 
-static struct irq_chip tegra_gpio_irq_chip = {
-	.name		= "GPIO",
-	.irq_ack	= tegra_gpio_irq_ack,
-	.irq_mask	= tegra_gpio_irq_mask,
-	.irq_unmask	= tegra_gpio_irq_unmask,
-	.irq_set_type	= tegra_gpio_irq_set_type,
-	.irq_shutdown	= tegra_gpio_irq_shutdown,
-#ifdef CONFIG_PM_SLEEP
-	.irq_set_wake	= tegra_gpio_irq_set_wake,
-#endif
-};
-
 static const struct dev_pm_ops tegra_gpio_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(tegra_gpio_suspend, tegra_gpio_resume)
 };
 
-/* This lock class tells lockdep that GPIO irqs are in a different
- * category than their parents, so it won't report false recursion.
- */
-static struct lock_class_key gpio_lock_class;
-
 static int tegra_gpio_probe(struct platform_device *pdev)
 {
 	const struct tegra_gpio_soc_config *config;
+	struct tegra_gpio_info *tgi;
 	struct resource *res;
 	struct tegra_gpio_bank *bank;
 	int ret;
@@ -465,88 +488,111 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 	int i;
 	int j;
 
-	dev = &pdev->dev;
-
 	config = of_device_get_match_data(&pdev->dev);
 	if (!config) {
 		dev_err(&pdev->dev, "Error: No device match found\n");
 		return -ENODEV;
 	}
 
-	tegra_gpio_bank_stride = config->bank_stride;
-	tegra_gpio_upper_offset = config->upper_offset;
+	tgi = devm_kzalloc(&pdev->dev, sizeof(*tgi), GFP_KERNEL);
+	if (!tgi)
+		return -ENODEV;
+
+	tgi->soc = config;
+	tgi->dev = &pdev->dev;
 
 	for (;;) {
-		res = platform_get_resource(pdev, IORESOURCE_IRQ, tegra_gpio_bank_count);
+		res = platform_get_resource(pdev, IORESOURCE_IRQ,
+					    tgi->bank_count);
 		if (!res)
 			break;
-		tegra_gpio_bank_count++;
+		tgi->bank_count++;
 	}
-	if (!tegra_gpio_bank_count) {
+	if (!tgi->bank_count) {
 		dev_err(&pdev->dev, "Missing IRQ resource\n");
 		return -ENODEV;
 	}
 
-	tegra_gpio_chip.ngpio = tegra_gpio_bank_count * 32;
+	tgi->gc.label			= "tegra-gpio";
+	tgi->gc.request			= tegra_gpio_request;
+	tgi->gc.free			= tegra_gpio_free;
+	tgi->gc.direction_input		= tegra_gpio_direction_input;
+	tgi->gc.get			= tegra_gpio_get;
+	tgi->gc.direction_output	= tegra_gpio_direction_output;
+	tgi->gc.set			= tegra_gpio_set;
+	tgi->gc.to_irq			= tegra_gpio_to_irq;
+	tgi->gc.base			= 0;
+	tgi->gc.ngpio			= tgi->bank_count * 32;
+	tgi->gc.parent			= &pdev->dev;
+	tgi->gc.of_node			= pdev->dev.of_node;
+
+	tgi->ic.name			= "GPIO";
+	tgi->ic.irq_ack			= tegra_gpio_irq_ack;
+	tgi->ic.irq_mask		= tegra_gpio_irq_mask;
+	tgi->ic.irq_unmask		= tegra_gpio_irq_unmask;
+	tgi->ic.irq_set_type		= tegra_gpio_irq_set_type;
+	tgi->ic.irq_shutdown		= tegra_gpio_irq_shutdown;
+#ifdef CONFIG_PM_SLEEP
+	tgi->ic.irq_set_wake		= tegra_gpio_irq_set_wake;
+#endif
+
+	platform_set_drvdata(pdev, tgi);
 
-	tegra_gpio_banks = devm_kzalloc(&pdev->dev,
-			tegra_gpio_bank_count * sizeof(*tegra_gpio_banks),
-			GFP_KERNEL);
-	if (!tegra_gpio_banks)
+	tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
+				      sizeof(*tgi->bank_info), GFP_KERNEL);
+	if (!tgi->bank_info)
 		return -ENODEV;
 
-	irq_domain = irq_domain_add_linear(pdev->dev.of_node,
-					   tegra_gpio_chip.ngpio,
-					   &irq_domain_simple_ops, NULL);
-	if (!irq_domain)
+	tgi->irq_domain = irq_domain_add_linear(pdev->dev.of_node,
+						tgi->gc.ngpio,
+						&irq_domain_simple_ops, NULL);
+	if (!tgi->irq_domain)
 		return -ENODEV;
 
-	for (i = 0; i < tegra_gpio_bank_count; i++) {
+	for (i = 0; i < tgi->bank_count; i++) {
 		res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
 		if (!res) {
 			dev_err(&pdev->dev, "Missing IRQ resource\n");
 			return -ENODEV;
 		}
 
-		bank = &tegra_gpio_banks[i];
+		bank = &tgi->bank_info[i];
 		bank->bank = i;
 		bank->irq = res->start;
+		bank->tgi = tgi;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	regs = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(regs))
-		return PTR_ERR(regs);
+	tgi->regs = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(tgi->regs))
+		return PTR_ERR(tgi->regs);
 
-	for (i = 0; i < tegra_gpio_bank_count; i++) {
+	for (i = 0; i < tgi->bank_count; i++) {
 		for (j = 0; j < 4; j++) {
 			int gpio = tegra_gpio_compose(i, j, 0);
-			tegra_gpio_writel(0x00, GPIO_INT_ENB(gpio));
+			tegra_gpio_writel(tgi, 0x00, GPIO_INT_ENB(tgi, gpio));
 		}
 	}
 
-	tegra_gpio_chip.of_node = pdev->dev.of_node;
-
-	ret = devm_gpiochip_add_data(&pdev->dev, &tegra_gpio_chip, NULL);
+	ret = devm_gpiochip_add_data(&pdev->dev, &tgi->gc, tgi);
 	if (ret < 0) {
-		irq_domain_remove(irq_domain);
+		irq_domain_remove(tgi->irq_domain);
 		return ret;
 	}
 
-	for (gpio = 0; gpio < tegra_gpio_chip.ngpio; gpio++) {
-		int irq = irq_create_mapping(irq_domain, gpio);
+	for (gpio = 0; gpio < tgi->gc.ngpio; gpio++) {
+		int irq = irq_create_mapping(tgi->irq_domain, gpio);
 		/* No validity check; all Tegra GPIOs are valid IRQs */
 
-		bank = &tegra_gpio_banks[GPIO_BANK(gpio)];
+		bank = &tgi->bank_info[GPIO_BANK(gpio)];
 
-		irq_set_lockdep_class(irq, &gpio_lock_class);
+		irq_set_lockdep_class(irq, &tgi->lock_class);
 		irq_set_chip_data(irq, bank);
-		irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip,
-					 handle_simple_irq);
+		irq_set_chip_and_handler(irq, &tgi->ic, handle_simple_irq);
 	}
 
-	for (i = 0; i < tegra_gpio_bank_count; i++) {
-		bank = &tegra_gpio_banks[i];
+	for (i = 0; i < tgi->bank_count; i++) {
+		bank = &tgi->bank_info[i];
 
 		irq_set_chained_handler_and_data(bank->irq,
 						 tegra_gpio_irq_handler, bank);
@@ -555,7 +601,7 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 			spin_lock_init(&bank->lvl_lock[j]);
 	}
 
-	tegra_gpio_debuginit();
+	tegra_gpio_debuginit(tgi);
 
 	return 0;
 }
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce
  2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
                   ` (2 preceding siblings ...)
  2016-04-25 10:38 ` [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables Laxman Dewangan
@ 2016-04-25 10:38 ` Laxman Dewangan
  2016-04-28  5:58   ` Alexandre Courbot
  2016-04-29  9:03   ` Linus Walleij
  2016-04-29  9:07 ` [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Linus Walleij
  4 siblings, 2 replies; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-25 10:38 UTC (permalink / raw)
  To: swarren, linus.walleij, gnurou, thierry.reding, linux-gpio,
	linux-tegra, linux-kernel
  Cc: Laxman Dewangan

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>

---
Changes from V1:
- Write debounce count before enable.
- Make sure the debounce count do not have any boot residuals.

Changes from V2:
- Only access register for debounce when SoC support debounce.

Changes from V3:
- Add locking mechanism in debounce count register update.
- Move DBC register from prev patch to here.

Changes from V3:
- Rewrite the set_debounce to have bank_info as local pointer for easy to read.
- Collected RB from Stephen.
---
 drivers/gpio/gpio-tegra.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 68 insertions(+), 1 deletion(-)

diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 653825d..b3ddd92 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -46,10 +46,13 @@
 #define GPIO_INT_ENB(t, x)	(GPIO_REG(t, x) + 0x50)
 #define GPIO_INT_LVL(t, x)	(GPIO_REG(t, x) + 0x60)
 #define GPIO_INT_CLR(t, x)	(GPIO_REG(t, x) + 0x70)
+#define GPIO_DBC_CNT(t, x)	(GPIO_REG(t, x) + 0xF0)
+
 
 #define GPIO_MSK_CNF(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x00)
 #define GPIO_MSK_OE(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x10)
 #define GPIO_MSK_OUT(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0X20)
+#define GPIO_MSK_DBC_EN(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x30)
 #define GPIO_MSK_INT_STA(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x40)
 #define GPIO_MSK_INT_ENB(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x50)
 #define GPIO_MSK_INT_LVL(t, x)	(GPIO_REG(t, x) + t->soc->upper_offset + 0x60)
@@ -67,6 +70,7 @@ struct tegra_gpio_bank {
 	int bank;
 	int irq;
 	spinlock_t lvl_lock[4];
+	spinlock_t dbc_lock[4];	/* Lock for updating debounce count register */
 #ifdef CONFIG_PM_SLEEP
 	u32 cnf[4];
 	u32 out[4];
@@ -74,11 +78,14 @@ struct tegra_gpio_bank {
 	u32 int_enb[4];
 	u32 int_lvl[4];
 	u32 wake_enb[4];
+	u32 dbc_enb[4];
 #endif
+	u32 dbc_cnt[4];
 	struct tegra_gpio_info *tgi;
 };
 
 struct tegra_gpio_soc_config {
+	bool debounce_supported;
 	u32 bank_stride;
 	u32 upper_offset;
 };
@@ -184,6 +191,39 @@ static int tegra_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 	return 0;
 }
 
+static int tegra_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,
+				   unsigned int debounce)
+{
+	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
+	struct tegra_gpio_bank *bank = &tgi->bank_info[GPIO_BANK(offset)];
+	unsigned int debounce_ms = DIV_ROUND_UP(debounce, 1000);
+	unsigned long flags;
+	int port;
+
+	if (!debounce_ms) {
+		tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset),
+				      offset, 0);
+		return 0;
+	}
+
+	debounce_ms = min(debounce_ms, 255U);
+	port = GPIO_PORT(offset);
+
+	/* There is only one debounce count register per port and hence
+	 * set the maximum of current and requested debounce time.
+	 */
+	spin_lock_irqsave(&bank->dbc_lock[port], flags);
+	if (bank->dbc_cnt[port] < debounce_ms) {
+		tegra_gpio_writel(tgi, debounce_ms, GPIO_DBC_CNT(tgi, offset));
+		bank->dbc_cnt[port] = debounce_ms;
+	}
+	spin_unlock_irqrestore(&bank->dbc_lock[port], flags);
+
+	tegra_gpio_mask_write(tgi, GPIO_MSK_DBC_EN(tgi, offset), offset, 1);
+
+	return 0;
+}
+
 static int tegra_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
 	struct tegra_gpio_info *tgi = gpiochip_get_data(chip);
@@ -350,6 +390,14 @@ static int tegra_gpio_resume(struct device *dev)
 			unsigned int gpio = (b<<5) | (p<<3);
 			tegra_gpio_writel(tgi, bank->cnf[p],
 					  GPIO_CNF(tgi, gpio));
+
+			if (tgi->soc->debounce_supported) {
+				tegra_gpio_writel(tgi, bank->dbc_cnt[p],
+						  GPIO_DBC_CNT(tgi, gpio));
+				tegra_gpio_writel(tgi, bank->dbc_enb[p],
+						  GPIO_MSK_DBC_EN(tgi, gpio));
+			}
+
 			tegra_gpio_writel(tgi, bank->out[p],
 					  GPIO_OUT(tgi, gpio));
 			tegra_gpio_writel(tgi, bank->oe[p],
@@ -385,6 +433,13 @@ static int tegra_gpio_suspend(struct device *dev)
 							GPIO_OUT(tgi, gpio));
 			bank->oe[p] = tegra_gpio_readl(tgi,
 						       GPIO_OE(tgi, gpio));
+			if (tgi->soc->debounce_supported) {
+				bank->dbc_enb[p] = tegra_gpio_readl(tgi,
+						GPIO_MSK_DBC_EN(tgi, gpio));
+				bank->dbc_enb[p] = (bank->dbc_enb[p] << 8) |
+							bank->dbc_enb[p];
+			}
+
 			bank->int_enb[p] = tegra_gpio_readl(tgi,
 						GPIO_INT_ENB(tgi, gpio));
 			bank->int_lvl[p] = tegra_gpio_readl(tgi,
@@ -538,6 +593,9 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, tgi);
 
+	if (config->debounce_supported)
+		tgi->gc.set_debounce = tegra_gpio_set_debounce;
+
 	tgi->bank_info = devm_kzalloc(&pdev->dev, tgi->bank_count *
 				      sizeof(*tgi->bank_info), GFP_KERNEL);
 	if (!tgi->bank_info)
@@ -597,8 +655,10 @@ static int tegra_gpio_probe(struct platform_device *pdev)
 		irq_set_chained_handler_and_data(bank->irq,
 						 tegra_gpio_irq_handler, bank);
 
-		for (j = 0; j < 4; j++)
+		for (j = 0; j < 4; j++) {
 			spin_lock_init(&bank->lvl_lock[j]);
+			spin_lock_init(&bank->dbc_lock[j]);
+		}
 	}
 
 	tegra_gpio_debuginit(tgi);
@@ -616,7 +676,14 @@ static const struct tegra_gpio_soc_config tegra30_gpio_config = {
 	.upper_offset = 0x80,
 };
 
+static const struct tegra_gpio_soc_config tegra210_gpio_config = {
+	.debounce_supported = true,
+	.bank_stride = 0x100,
+	.upper_offset = 0x80,
+};
+
 static const struct of_device_id tegra_gpio_of_match[] = {
+	{ .compatible = "nvidia,tegra210-gpio", .data = &tegra210_gpio_config },
 	{ .compatible = "nvidia,tegra30-gpio", .data = &tegra30_gpio_config },
 	{ .compatible = "nvidia,tegra20-gpio", .data = &tegra20_gpio_config },
 	{ },
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce
  2016-04-25 10:38 ` [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce Laxman Dewangan
@ 2016-04-28  5:58   ` Alexandre Courbot
  2016-04-29  9:03   ` Linus Walleij
  1 sibling, 0 replies; 19+ messages in thread
From: Alexandre Courbot @ 2016-04-28  5:58 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Linus Walleij, Thierry Reding, linux-gpio,
	linux-tegra, Linux Kernel Mailing List

On Mon, Apr 25, 2016 at 7:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
> 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>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data()
  2016-04-25 10:38 ` [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data() Laxman Dewangan
@ 2016-04-29  8:59   ` Linus Walleij
  0 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2016-04-29  8:59 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> Use of_device_get_match_data() for getting matched data
> instead of implementing this locally.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@nvidia.com>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
> Acked-by: Thierry Reding <treding@nvidia.com>

Oops sorry, backed out the v2 and applied this v5 version
instead.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant
  2016-04-25 10:38 ` [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant Laxman Dewangan
@ 2016-04-29  9:00   ` Linus Walleij
  0 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2016-04-29  9:00 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> The data member of the of_device_id is the constant type
> and hence all static structure which is used for this
> initialisation as static.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> Suggested-by: Thierry Reding <treding@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@nvidia.com>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables
  2016-04-25 10:38 ` [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables Laxman Dewangan
@ 2016-04-29  9:01   ` Linus Walleij
  0 siblings, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2016-04-29  9:01 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> Move the file scoped multiple global variable from Tegra GPIO
> driver to the structure and make this as gpiochip data which
> can be referred from GPIO chip callbacks.
>
> Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com>
> Reviewed-by: Stephen Warren <swarren@nvidia.com>
> Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>

Patch applied.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce
  2016-04-25 10:38 ` [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce Laxman Dewangan
  2016-04-28  5:58   ` Alexandre Courbot
@ 2016-04-29  9:03   ` Linus Walleij
  1 sibling, 0 replies; 19+ messages in thread
From: Linus Walleij @ 2016-04-29  9:03 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> 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>

Patch applied, also added Alex' review tag.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
                   ` (3 preceding siblings ...)
  2016-04-25 10:38 ` [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce Laxman Dewangan
@ 2016-04-29  9:07 ` Linus Walleij
  2016-04-29  9:20   ` Laxman Dewangan
  4 siblings, 1 reply; 19+ messages in thread
From: Linus Walleij @ 2016-04-29  9:07 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:

> Add support for the debounce as Tegra210 support debounce in HW.
> Also do the clenaups to remove all global variables.

OK this v5 is applied.

Laxman does this GPIO also have open drain and/or open source
handling?

Then you might want to look into supporting that too as I just added
support for native single-endedness to gpiolib, c.f.:
http://marc.info/?l=linux-gpio&m=146011780301280&w=2

It would be nice if you also implement .get_direction() which
makes debugfs and initial reading of the state of the lines
more accurate.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-04-29  9:07 ` [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Linus Walleij
@ 2016-04-29  9:20   ` Laxman Dewangan
  2016-04-30 11:07     ` Linus Walleij
  0 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-04-29  9:20 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel


On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
>
>> Add support for the debounce as Tegra210 support debounce in HW.
>> Also do the clenaups to remove all global variables.
> OK this v5 is applied.
>
> Laxman does this GPIO also have open drain and/or open source
> handling?

Some of the pins support the open drain and these are part of pinmux 
register set.
For that we have property for setting open drain.

Is it possible to link the gpio APIs to pincontrol for setting that pin?


> Then you might want to look into supporting that too as I just added
> support for native single-endedness to gpiolib, c.f.:
> http://marc.info/?l=linux-gpio&m=146011780301280&w=2

Yaah, Some of PMIC's (which I am handling) gpios support open drain and 
I think I can have changes for the PMIC gpio driver.

>
> It would be nice if you also implement .get_direction() which
> makes debugfs and initial reading of the state of the lines
> more accurate.

Sure, this can be implemented.
Will post the patch on top of the series soon.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-04-29  9:20   ` Laxman Dewangan
@ 2016-04-30 11:07     ` Linus Walleij
  2016-05-02  6:44       ` Laxman Dewangan
  2016-05-02 16:12       ` Stephen Warren
  0 siblings, 2 replies; 19+ messages in thread
From: Linus Walleij @ 2016-04-30 11:07 UTC (permalink / raw)
  To: Laxman Dewangan
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel

On Fri, Apr 29, 2016 at 11:20 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
> On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
>> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com>
>> wrote:
>>
>>> Add support for the debounce as Tegra210 support debounce in HW.
>>> Also do the clenaups to remove all global variables.
>>
>> OK this v5 is applied.
>>
>> Laxman does this GPIO also have open drain and/or open source
>> handling?
>
>
> Some of the pins support the open drain and these are part of pinmux
> register set.
> For that we have property for setting open drain.
>
> Is it possible to link the gpio APIs to pincontrol for setting that pin?

I have the same issue with Nomadik pin control that I use as a
testbed: there is a backend in pin control to the GPIO side.

I was thinking about adding a new cross call. We now have this:

/* External interface to pin control */
extern int pinctrl_request_gpio(unsigned gpio);
extern void pinctrl_free_gpio(unsigned gpio);
extern int pinctrl_gpio_direction_input(unsigned gpio);
extern int pinctrl_gpio_direction_output(unsigned gpio);

I was going to add:

extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);

That can be used by GPIO drivers to call back into pincontrol
and set up any config flags using the conventions of the
corresponding pin control back-end.

This could be used for as well open drain as other things (like
pull-up) as the userspace ABI matures (it currently only has
in/out and open drain/source).

What do you think about this idea?

>> Then you might want to look into supporting that too as I just added
>> support for native single-endedness to gpiolib, c.f.:
>> http://marc.info/?l=linux-gpio&m=146011780301280&w=2
>
> Yaah, Some of PMIC's (which I am handling) gpios support open drain and I
> think I can have changes for the PMIC gpio driver.

Nice! :)

>> It would be nice if you also implement .get_direction() which
>> makes debugfs and initial reading of the state of the lines
>> more accurate.
>
> Sure, this can be implemented.
> Will post the patch on top of the series soon.

Thanks.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-04-30 11:07     ` Linus Walleij
@ 2016-05-02  6:44       ` Laxman Dewangan
  2016-05-02 16:12       ` Stephen Warren
  1 sibling, 0 replies; 19+ messages in thread
From: Laxman Dewangan @ 2016-05-02  6:44 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Stephen Warren, Alexandre Courbot, Thierry Reding, linux-gpio,
	linux-tegra, linux-kernel


On Saturday 30 April 2016 04:37 PM, Linus Walleij wrote:
> On Fri, Apr 29, 2016 at 11:20 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
>> On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
>>> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com>
>>> wrote:
>>>
>>>> Add support for the debounce as Tegra210 support debounce in HW.
>>>> Also do the clenaups to remove all global variables.
>>> OK this v5 is applied.
>>>
>>> Laxman does this GPIO also have open drain and/or open source
>>> handling?
>>
>> Some of the pins support the open drain and these are part of pinmux
>> register set.
>> For that we have property for setting open drain.
>>
>> Is it possible to link the gpio APIs to pincontrol for setting that pin?
> I have the same issue with Nomadik pin control that I use as a
> testbed: there is a backend in pin control to the GPIO side.
>
> I was thinking about adding a new cross call. We now have this:
>
> /* External interface to pin control */
> extern int pinctrl_request_gpio(unsigned gpio);
> extern void pinctrl_free_gpio(unsigned gpio);
> extern int pinctrl_gpio_direction_input(unsigned gpio);
> extern int pinctrl_gpio_direction_output(unsigned gpio);
>
> I was going to add:
>
> extern int pinctrl_gpio_set_config(unsigned gpio, unsigned long config);
>
> That can be used by GPIO drivers to call back into pincontrol
> and set up any config flags using the conventions of the
> corresponding pin control back-end.
>
> This could be used for as well open drain as other things (like
> pull-up) as the userspace ABI matures (it currently only has
> in/out and open drain/source).
>
> What do you think about this idea?
>

Yes, this will be great.
We will have generic interface which help in extending it in option.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-04-30 11:07     ` Linus Walleij
  2016-05-02  6:44       ` Laxman Dewangan
@ 2016-05-02 16:12       ` Stephen Warren
  2016-05-02 17:58         ` Laxman Dewangan
  1 sibling, 1 reply; 19+ messages in thread
From: Stephen Warren @ 2016-05-02 16:12 UTC (permalink / raw)
  To: Linus Walleij, Laxman Dewangan
  Cc: Alexandre Courbot, Thierry Reding, linux-gpio, linux-tegra, linux-kernel

On 04/30/2016 05:07 AM, Linus Walleij wrote:
> On Fri, Apr 29, 2016 at 11:20 AM, Laxman Dewangan <ldewangan@nvidia.com> wrote:
>> On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
>>> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan <ldewangan@nvidia.com>
>>> wrote:
>>>
>>>> Add support for the debounce as Tegra210 support debounce in HW.
>>>> Also do the clenaups to remove all global variables.
>>>
>>> OK this v5 is applied.
>>>
>>> Laxman does this GPIO also have open drain and/or open source
>>> handling?
>>
>>
>> Some of the pins support the open drain and these are part of pinmux
>> register set.
>> For that we have property for setting open drain.

IIRC, Tegra has open-drain control in both the GPIO controller for all 
pins (OE bit) and in the pinmux controller for a small subset of pins. 
For GPIOs, why wouldn't we just use the control bit in the GPIO 
controller for all GPIOs. This would avoid any special-cases, and 
minimize coupling between the GPIO and pinctrl drivers.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-05-02 16:12       ` Stephen Warren
@ 2016-05-02 17:58         ` Laxman Dewangan
  2016-05-02 18:44           ` Stephen Warren
  0 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-05-02 17:58 UTC (permalink / raw)
  To: Stephen Warren, Linus Walleij
  Cc: Alexandre Courbot, Thierry Reding, linux-gpio, linux-tegra, linux-kernel


On Monday 02 May 2016 09:42 PM, Stephen Warren wrote:
> On 04/30/2016 05:07 AM, Linus Walleij wrote:
>> On Fri, Apr 29, 2016 at 11:20 AM, Laxman Dewangan 
>> <ldewangan@nvidia.com> wrote:
>>> On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
>>>> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan 
>>>> <ldewangan@nvidia.com>
>>>> wrote:
>>>>
>>>>> Add support for the debounce as Tegra210 support debounce in HW.
>>>>> Also do the clenaups to remove all global variables.
>>>>
>>>> OK this v5 is applied.
>>>>
>>>> Laxman does this GPIO also have open drain and/or open source
>>>> handling?
>>>
>>>
>>> Some of the pins support the open drain and these are part of pinmux
>>> register set.
>>> For that we have property for setting open drain.
>
> IIRC, Tegra has open-drain control in both the GPIO controller for all 
> pins (OE bit) and in the pinmux controller for a small subset of pins. 
> For GPIOs, why wouldn't we just use the control bit in the GPIO 
> controller for all GPIOs. This would avoid any special-cases, and 
> minimize coupling between the GPIO and pinctrl drivers.


Toggling OE bit is something emulating the open drain here.

I think idea is that when we configure the pin in open drain then it 
should be automatically handled by HW  when we want to set pin state 
high or low. When we set low, the pin should be driven and when high 
then it should be tristated input. We should not need any direction bit 
setting.

Otherwise, if pin is configured as open drain then:

Set out = 0

and when it need to set pin to high then oe = 0 else oe =1. Do not 
toggle any other bits.

On this case, we need to store that pin is configured as open drain so 
that set_value should toggle OE instead of OUT.

Or do you want to have different implementation?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-05-02 17:58         ` Laxman Dewangan
@ 2016-05-02 18:44           ` Stephen Warren
  2016-05-02 19:06             ` Laxman Dewangan
  0 siblings, 1 reply; 19+ messages in thread
From: Stephen Warren @ 2016-05-02 18:44 UTC (permalink / raw)
  To: Laxman Dewangan, Linus Walleij
  Cc: Alexandre Courbot, Thierry Reding, linux-gpio, linux-tegra, linux-kernel

On 05/02/2016 11:58 AM, Laxman Dewangan wrote:
>
> On Monday 02 May 2016 09:42 PM, Stephen Warren wrote:
>> On 04/30/2016 05:07 AM, Linus Walleij wrote:
>>> On Fri, Apr 29, 2016 at 11:20 AM, Laxman Dewangan
>>> <ldewangan@nvidia.com> wrote:
>>>> On Friday 29 April 2016 02:37 PM, Linus Walleij wrote:
>>>>> On Mon, Apr 25, 2016 at 12:38 PM, Laxman Dewangan
>>>>> <ldewangan@nvidia.com>
>>>>> wrote:
>>>>>
>>>>>> Add support for the debounce as Tegra210 support debounce in HW.
>>>>>> Also do the clenaups to remove all global variables.
>>>>>
>>>>> OK this v5 is applied.
>>>>>
>>>>> Laxman does this GPIO also have open drain and/or open source
>>>>> handling?
>>>>
>>>>
>>>> Some of the pins support the open drain and these are part of pinmux
>>>> register set.
>>>> For that we have property for setting open drain.
>>
>> IIRC, Tegra has open-drain control in both the GPIO controller for all
>> pins (OE bit) and in the pinmux controller for a small subset of pins.
>> For GPIOs, why wouldn't we just use the control bit in the GPIO
>> controller for all GPIOs. This would avoid any special-cases, and
>> minimize coupling between the GPIO and pinctrl drivers.
>
>
> Toggling OE bit is something emulating the open drain here.

 From the perspective of the external HW that's attached to the GPIO, I 
believe there's no difference.

> I think idea is that when we configure the pin in open drain then it
> should be automatically handled by HW  when we want to set pin state
> high or low. When we set low, the pin should be driven and when high
> then it should be tristated input. We should not need any direction bit
> setting.

I don't imagine anything in the kernel cares, so long as the correct 
logic level is present on the pin based on whatever GPIO API was last 
called.

I'd be very surprised if there wasn't hardware that could only implement 
open-drain by this "emulation" method, so I'd be very surprised if 
something prohibited that implementation style.

> Otherwise, if pin is configured as open drain then:
>
> Set out = 0
>
> and when it need to set pin to high then oe = 0 else oe =1. Do not
> toggle any other bits.
>
> On this case, we need to store that pin is configured as open drain so
> that set_value should toggle OE instead of OUT.

That sounds like a reasonable implementation.

> Or do you want to have different implementation?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-05-02 18:44           ` Stephen Warren
@ 2016-05-02 19:06             ` Laxman Dewangan
  2016-05-03 15:59               ` Stephen Warren
  0 siblings, 1 reply; 19+ messages in thread
From: Laxman Dewangan @ 2016-05-02 19:06 UTC (permalink / raw)
  To: Stephen Warren, Linus Walleij
  Cc: Alexandre Courbot, Thierry Reding, linux-gpio, linux-tegra, linux-kernel


On Tuesday 03 May 2016 12:14 AM, Stephen Warren wrote:
> On 05/02/2016 11:58 AM, Laxman Dewangan wrote:
>>
>>
>> Toggling OE bit is something emulating the open drain here.
>
> From the perspective of the external HW that's attached to the GPIO, I 
> believe there's no difference.
>
>> I think idea is that when we configure the pin in open drain then it
>> should be automatically handled by HW  when we want to set pin state
>> high or low. When we set low, the pin should be driven and when high
>> then it should be tristated input. We should not need any direction bit
>> setting.
>
> I don't imagine anything in the kernel cares, so long as the correct 
> logic level is present on the pin based on whatever GPIO API was last 
> called.
>
> I'd be very surprised if there wasn't hardware that could only 
> implement open-drain by this "emulation" method, so I'd be very 
> surprised if something prohibited that implementation style.
>

The emulation method implemented just to not drive high for open drain.
Recently, proper callback added for hw control for open drain and hence 
emulation method is not needed for such HW.

I think if HW support the callback to implement the open drain then use 
the HW method otherwise fallback to emulation method.


>> Otherwise, if pin is configured as open drain then:
>>
>> Set out = 0
>>
>> and when it need to set pin to high then oe = 0 else oe =1. Do not
>> toggle any other bits.
>>
>> On this case, we need to store that pin is configured as open drain so
>> that set_value should toggle OE instead of OUT.
>
> That sounds like a reasonable implementation.
>

Let me create the patch for review and further discussion.

>> Or do you want to have different implementation?
>

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce
  2016-05-02 19:06             ` Laxman Dewangan
@ 2016-05-03 15:59               ` Stephen Warren
  0 siblings, 0 replies; 19+ messages in thread
From: Stephen Warren @ 2016-05-03 15:59 UTC (permalink / raw)
  To: Laxman Dewangan, Linus Walleij
  Cc: Alexandre Courbot, Thierry Reding, linux-gpio, linux-tegra, linux-kernel

On 05/02/2016 01:06 PM, Laxman Dewangan wrote:
>
> On Tuesday 03 May 2016 12:14 AM, Stephen Warren wrote:
>> On 05/02/2016 11:58 AM, Laxman Dewangan wrote:
>>>
>>>
>>> Toggling OE bit is something emulating the open drain here.
>>
>> From the perspective of the external HW that's attached to the GPIO, I
>> believe there's no difference.
>>
>>> I think idea is that when we configure the pin in open drain then it
>>> should be automatically handled by HW  when we want to set pin state
>>> high or low. When we set low, the pin should be driven and when high
>>> then it should be tristated input. We should not need any direction bit
>>> setting.
>>
>> I don't imagine anything in the kernel cares, so long as the correct
>> logic level is present on the pin based on whatever GPIO API was last
>> called.
>>
>> I'd be very surprised if there wasn't hardware that could only
>> implement open-drain by this "emulation" method, so I'd be very
>> surprised if something prohibited that implementation style.
>>
>
> The emulation method implemented just to not drive high for open drain.
> Recently, proper callback added for hw control for open drain and hence
> emulation method is not needed for such HW.
>
> I think if HW support the callback to implement the open drain then use
> the HW method otherwise fallback to emulation method.

I don't see any benefit to that. It makes the code more complex without 
enabling any more features.

For reference, on Tegra124 and earlier, very few pins have open-drain 
control in HW (pinmux) whereas you can emulate it in the GPIO module for 
any pin. In Tegra210 and Tegra186, many pins have open-drain control in 
HW (pinmux) yet a good number still don't, yet you can still emulate 
this in the GPIO module for any pin.

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2016-05-03 15:59 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-25 10:38 [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Laxman Dewangan
2016-04-25 10:38 ` [PATCH V5 1/4] gpio: tegra: Don't open code of_device_get_match_data() Laxman Dewangan
2016-04-29  8:59   ` Linus Walleij
2016-04-25 10:38 ` [PATCH V5 2/4] gpio: tegra: Make of_device_id compatible data to constant Laxman Dewangan
2016-04-29  9:00   ` Linus Walleij
2016-04-25 10:38 ` [PATCH V5 3/4] gpio: tegra: Get rid of all file scoped global variables Laxman Dewangan
2016-04-29  9:01   ` Linus Walleij
2016-04-25 10:38 ` [PATCH V5 4/4] gpio: tegra: Add support for gpio debounce Laxman Dewangan
2016-04-28  5:58   ` Alexandre Courbot
2016-04-29  9:03   ` Linus Walleij
2016-04-29  9:07 ` [PATCH V5 0/4] gpio: tegra: Cleanups and support for debounce Linus Walleij
2016-04-29  9:20   ` Laxman Dewangan
2016-04-30 11:07     ` Linus Walleij
2016-05-02  6:44       ` Laxman Dewangan
2016-05-02 16:12       ` Stephen Warren
2016-05-02 17:58         ` Laxman Dewangan
2016-05-02 18:44           ` Stephen Warren
2016-05-02 19:06             ` Laxman Dewangan
2016-05-03 15:59               ` Stephen Warren

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).