Skip to contentSkip to conversation

gpio/omap: driver cleanup and fixes

PATCH Superseded Tarun Kanti DebBarma 3 participants 55 messages Aug 31, 2011 – Sep 12, 2011

Subsystems (7)

v6 of 9 Superseded Latest is v9 →

lore
Share & tools
lore
#0 lore raw

v6 cover gpio/omap: driver cleanup and fixes

This series is continuation of cleanup of OMAP GPIO driver and fixes. The cleanup include getting rid of cpu_is_* checks wherever possible, use of gpio_bank list instead of static array, use of unique platform specific value associated data member to OMAP platforms to avoid cpu_is_* checks. The series also include PM runtime support.*

Baseline: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Branch: master
Commit: c6a389f Linux 3.1-rc4

Test Details:
- Compile tested for omap1_defconfig and omap2plus_defconfig.
- OMAP1710-H3: Bootup test pending due to non-availability of setup. As soon as the setup is available I will boot test and intimate.
- OMAP2430/SDP, OMAP3430/SDP, OMAP4430/SDP, OMAP4430/Blaze: Functional testing.
- PM Testing on OMAP3430-SDP: retention, off_mode, system_wide suspend and gpio wakeup.

v6:
- Save and restore debounce registers for proper driver operation.

- Restore interrupt enable after all configuration to avoid spurious interrupts.

- Restore dataout register before oe register.

- Restore dataout into dataout_set or dataout based upon the OMAP version.

- Change register name from wkup_status to wkup_en.

- Remove wrapper around omap_pm_get_dev_context_loss_count(). Use it directly. Also, changed the signature of get_context_loss_count in pdata and bank structure from int to u32.

- Use 'context' instead of 'ctx' for clarity wherever it is used.

- Merged two patches into one which are related to bank_is_mpuio() modification.

- Use shift operator instead of following:
+ .irqctrl = OMAP_MPUIO_GPIO_INT_EDGE / 2,

- Remove redundant check from the following
+ if (bank_is_mpuio(bank)) {
+ if (bank->regs->wkup_status) <--- redundant check
+ mpuio_init(bank);

- Change subject of following patch
[PATCH v5 15/22] gpio/omap: use readl in irq_handler for all access into
[PATCH 14/25] gpio/omap: remove unnecessary bit-masking for read access

- Fix multi-line comments in
[PATCH v5 20/22] gpio/omap: cleanup prepare_for_idle and resume_after_idle

v5:
- Reduce runtime callback overhead when *_get/put_sync() called from probe() and *_gpio_request/free().

- Dynamic context save within functions where context is modified instead of saving all context within a common function.

- Removed call to mpuio_init() from omap_gpio_mod_init(). Both the functions are called once during initialization in *_gpio_probe().
Call to omap_gpio_mod_init() has been removed from omap_gpio_request() on the first access to gpio bank. One time initialization looks sufficient.

- In *_gpio_irq_handler() use *_put_sync_suspend() instead of *_put_sync().

- Removed hardcoding of OMAP16xx sysconfig register value and instead defined an associated constant.

- Removed *_get_sync() call from *_gpio_suspend() and *_put_sync() call from *_gpio_resume(). They got wrongly slipped into the code.

- Removed following redundant zero allocated initialization from mach-omap2/gpio.c
+ pdata->regs->irqctrl = 0;
+ pdata->regs->edgectrl1 = 0;
+ pdata->regs->edgectrl2 = 0;

- Removed following redundant code in gpio-omap.c
-#define bank_is_mpuio(bank) ((bank)->method == METHOD_MPUIO)

v4:
- since all accesses to registers are 4-byte aligned, removing special checks and handling of 16 and 32-bit wide bank registers and instead use 32-bit read/write access consistently.

- redundant usage of MOD_REG_BIT has been corrected and replaced with _gpio_rmw().

- omap_gpio_mod_init() function has been simplified further using _gpio_rmw().

- sysconfig register offset specific to omap16xx has been removed along with its usage.

- additional logic to skip from suspend/resume:

  if (!bank->regs->wkup_status || !bank->suspend_wakeup)
  	return 0;
  
  if (!bank->regs->wkup_status || !bank->saved_wakeup)
  	return 0;

- separated mpuio related changes into a different patch from the patch where wakeup status register related changes are done.

- Incorrect replacement of !cpu_class_is_omap2() in gpio_irq_type() corrected:
+ if (!bank->regs->leveldetect0 &&
+ (type & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)))
return -EINVAL;

v3:
- Avoid use of wkup_set and wkup_clear registers. Instead use wkup_status register for all platforms. This is because on OMAP4 it is recommended not to use them.

- Remove duplicate code in omap_gpio_mod_init() for handling the same for 32-bit and 16-bit GPIO bank widths. This is accomplished by having two functions to handle each case while assiging a common function pointer during initialization.

- Remove OMAP16xx specific one time initialization from omap_gpio_mod_init(). Move it inside omap16xx_gpio_init().

- Avoid usage of USHRT_MAX to indicate undefined values. Use 0 instead.

- In omap_gpio_suspend()/resume() functions remove code that checks if the feature is supported. Instead, assign these functions to struct platform_driver's suspend & resume function pointers for those OMAP platforms whcih support this feature.

- Remove 'suspend_support' flag because it is redundant. Instead use wkup_* registers to decode the same information.

- Restore context also when we don't know if the context is lost.

- Make omap_gpio_save_context() and omap_gpio_restore_context() static.

v2:
- Do special handling of non-wakeup GPIOs only on OMAP2420. Avoid this handling on OMAP3430.
- Isolate cleanups and fixes into separate set of patches. Keep the cleanup first followed by the fixes.
- Avoid calling omap_gpio_get_context_loss() directly and instead call it through function pointer in pdata initialized during init.
- workaround_enabled flag is not longer needed and is removed.
- Call pwrdm_post_transition() before calling omap_gpio_resume_after_idle().
- In omap2_gpio_resume_after_idle() do context restore before handling workaround.
- Use PM runtime framework.
- Modify register offset names to : wkup_status, wkup_clear, wkup_set. Also use 'base + offset' for readibility in all relevant places.
- Remove unwanted messages from commit section like TODO, etc.

Charulatha V (10):
gpio/omap: remove dependency on gpio_bank_count gpio/omap: use flag to identify wakeup domain gpio/omap: make gpio_context part of gpio_bank structure gpio/omap: fix pwrdm_post_transition call sequence gpio/omap: handle save/restore context in GPIO driver gpio/omap: make non-wakeup GPIO part of pdata gpio/omap: avoid cpu checks during module ena/disable gpio/omap: use pinctrl offset instead of macro gpio/omap: remove bank->method & METHOD_* macros gpio/omap: fix bankwidth for OMAP7xx MPUIO

Nishant Menon (1):
gpio/omap: save and restore debounce registers

Nishanth Menon (3):
gpio/omap: enable irq at the end of all configuration in restore gpio/omap: restore OE only after setting the output level gpio/omap: handle set_dataout reg capable IP on restore

Tarun Kanti DebBarma (11):
gpio/omap: further cleanup using wkup_en register gpio/omap: use level/edge detect reg offsets gpio/omap: remove hardcoded offsets in context save/restore gpio/omap: cleanup set_gpio_triggering function gpio/omap: cleanup omap_gpio_mod_init function gpio/omap: remove unnecessary bit-masking for read access gpio/omap: use pm-runtime framework
gpio/omap: optimize suspend and resume functions gpio/omap: cleanup prepare_for_idle and resume_after_idle gpio/omap: skip operations in runtime callbacks gpio/omap: remove omap_gpio_save_context overhead

 arch/arm/mach-omap1/gpio15xx.c         |    7 +-
 arch/arm/mach-omap1/gpio16xx.c         |   47 ++-
 arch/arm/mach-omap1/gpio7xx.c          |   14 +-
 arch/arm/mach-omap2/gpio.c             |   36 +-
 arch/arm/mach-omap2/pm34xx.c           |   21 +-
 arch/arm/plat-omap/include/plat/gpio.h |   29 +-
 drivers/gpio/gpio-omap.c               | 1067 +++++++++++++-------------------
 7 files changed, 530 insertions(+), 691 deletions(-)
#1 lore raw

PATCH v6 1/25 gpio/omap: remove dependency on gpio_bank_count

From: Charulatha V <[email protected]>

The gpio_bank_count is the count of number of GPIO devices in a SoC. Remove this dependency from the driver by using list. Also remove the dependency on array of pointers to gpio_bank struct of all GPIO devices.

---
 arch/arm/mach-omap1/gpio15xx.c         |    1 -
 arch/arm/mach-omap1/gpio16xx.c         |    2 -
 arch/arm/mach-omap1/gpio7xx.c          |    2 -
 arch/arm/mach-omap2/gpio.c             |    1 -
 arch/arm/plat-omap/include/plat/gpio.h |    3 -
 drivers/gpio/gpio-omap.c               |  163 ++++++++++++++++----------------
 6 files changed, 80 insertions(+), 92 deletions(-)
arch/arm/mach-omap1/gpio15xx.c +0 -1
index 399da4c..f8c15ea 100644
@@ -115,7 +115,6 @@ static int __init omap15xx_gpio_init(void)
 	platform_device_register(&omap15xx_mpu_gpio);
 	platform_device_register(&omap15xx_gpio);
 
-	gpio_bank_count = 2;
 	return 0;
 }
 postcore_initcall(omap15xx_gpio_init);
arch/arm/mach-omap1/gpio16xx.c +0 -2
index 0f399bd..df4bb44 100644
@@ -221,8 +221,6 @@ static int __init omap16xx_gpio_init(void)
 	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++)
 		platform_device_register(omap16xx_gpio_dev[i]);
 
-	gpio_bank_count = ARRAY_SIZE(omap16xx_gpio_dev);
-
 	return 0;
 }
 postcore_initcall(omap16xx_gpio_init);
arch/arm/mach-omap1/gpio7xx.c +0 -2
index 5ab63ea..923eaa1 100644
@@ -282,8 +282,6 @@ static int __init omap7xx_gpio_init(void)
 	for (i = 0; i < ARRAY_SIZE(omap7xx_gpio_dev); i++)
 		platform_device_register(omap7xx_gpio_dev[i]);
 
-	gpio_bank_count = ARRAY_SIZE(omap7xx_gpio_dev);
-
 	return 0;
 }
 postcore_initcall(omap7xx_gpio_init);
arch/arm/mach-omap2/gpio.c +0 -1
index 2765cdc..fb162fd 100644
@@ -121,7 +121,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 
 	omap_device_disable_idle_on_suspend(od);
 
-	gpio_bank_count++;
 	return 0;
 }
 
arch/arm/plat-omap/include/plat/gpio.h +0 -3
index 91e8de3..dd330ed 100644
@@ -202,9 +202,6 @@ struct omap_gpio_platform_data {
 	struct omap_gpio_reg_offs *regs;
 };
 
-/* TODO: Analyze removing gpio_bank_count usage from driver code */
-extern int gpio_bank_count;
-
 extern void omap2_gpio_prepare_for_idle(int off_mode);
 extern void omap2_gpio_resume_after_idle(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
drivers/gpio/gpio-omap.c +80 -83

317 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#2 lore raw

PATCH v6 2/25 gpio/omap: use flag to identify wakeup domain

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

In omap3, save/restore context is implemented for GPIO banks 2-6 as GPIO bank1 is in wakeup domain. Instead of identifying bank's power domain by bank id, use 'loses_context' flag which is filled by pwrdm_can_ever_lose_context() during dev_init.

For getting the powerdomain pointer, omap_hwmod_get_pwrdm() is used. omap_device_get_pwrdm() could not be used as the pwrdm information needs to be filled in pdata, whereas omap_device_get_pwrdm() could be used only after omap_device_build() call.

---
 arch/arm/mach-omap2/gpio.c             |    6 ++++++
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |   13 ++++++-------
 3 files changed, 13 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/gpio.c +6 -0
index fb162fd..9f3a007 100644
@@ -24,6 +24,8 @@
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
 
+#include "powerdomain.h"
+
 static struct omap_device_pm_latency omap_gpio_latency[] = {
 	[0] = {
 		.deactivate_func = omap_device_idle_hwmods,
@@ -39,6 +41,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 	struct omap_gpio_dev_attr *dev_attr;
 	char *name = "omap_gpio";
 	int id;
+	struct powerdomain *pwrdm;
 
 	/*
 	 * extract the device id from name field available in the
@@ -107,6 +110,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		return -EINVAL;
 	}
 
+	pwrdm = omap_hwmod_get_pwrdm(oh);
+	pdata->loses_context = pwrdm_can_ever_lose_context(pwrdm);
+
 	od = omap_device_build(name, id - 1, oh, pdata,
 				sizeof(*pdata),	omap_gpio_latency,
 				ARRAY_SIZE(omap_gpio_latency),
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index dd330ed..58d0bf2 100644
@@ -198,6 +198,7 @@ struct omap_gpio_platform_data {
 	int bank_width;		/* GPIO bank width */
 	int bank_stride;	/* Only needed for omap1 MPUIO */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
+	bool loses_context;	/* whether the bank would ever lose context */
 
 	struct omap_gpio_reg_offs *regs;
 };
drivers/gpio/gpio-omap.c +6 -7
index 14fced1..9a160d4 100644
@@ -56,6 +56,7 @@ struct gpio_bank {
 	u32 dbck_enable_mask;
 	struct device *dev;
 	bool dbck_flag;
+	bool loses_context;
 	int stride;
 	u32 width;
 	u16 id;
@@ -1172,7 +1173,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	bank->dbck_flag = pdata->dbck_flag;
 	bank->stride = pdata->bank_stride;
 	bank->width = pdata->bank_width;
-
+	bank->loses_context = pdata->loses_context;
 	bank->regs = pdata->regs;
 
 	if (bank->regs->set_dataout && bank->regs->clr_dataout)
@@ -1328,8 +1329,7 @@ void omap2_gpio_prepare_for_idle(int off_mode)
 		u32 l1 = 0, l2 = 0;
 		int j;
 
-		/* TODO: Do not use cpu_is_omap34xx */
-		if ((cpu_is_omap34xx()) && (bank->id == 0))
+		if (!bank->loses_context)
 			continue;
 
 		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
@@ -1396,8 +1396,7 @@ void omap2_gpio_resume_after_idle(void)
 		u32 l = 0, gen, gen0, gen1;
 		int j;
 
-		/* TODO: Do not use cpu_is_omap34xx */
-		if ((cpu_is_omap34xx()) && (bank->id == 0))
+		if (!bank->loses_context)
 			continue;
 
 		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
@@ -1496,7 +1495,7 @@ void omap_gpio_save_context(void)
 	list_for_each_entry(bank, &omap_gpio_list, node) {
 		i++;
 
-		if (bank->id == 0)
+		if (!bank->loses_context)
 			continue;
 
 		gpio_context[i].irqenable1 =
@@ -1530,7 +1529,7 @@ void omap_gpio_restore_context(void)
 	list_for_each_entry(bank, &omap_gpio_list, node) {
 		i++;
 
-		if (bank->id == 0)
+		if (!bank->loses_context)
 			continue;
 
 		__raw_writel(gpio_context[i].irqenable1,
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH v6 3/25 gpio/omap: make gpio_context part of gpio_bank structure

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

Currently gpio_context array used to save gpio bank's context, is used only for OMAP3 architecture. Move gpio_context as part of gpio_bank structure so that it can be specific to each gpio bank and can be used for any OMAP architecture

---
 drivers/gpio/gpio-omap.c |   76 ++++++++++++++++++++-------------------------
 1 files changed, 34 insertions(+), 42 deletions(-)
drivers/gpio/gpio-omap.c +34 -42
index 9a160d4..e83109c 100644
@@ -30,6 +30,19 @@
 
 static LIST_HEAD(omap_gpio_list);
 
+struct gpio_regs {
+	u32 irqenable1;
+	u32 irqenable2;
+	u32 wake_en;
+	u32 ctrl;
+	u32 oe;
+	u32 leveldetect0;
+	u32 leveldetect1;
+	u32 risingdetect;
+	u32 fallingdetect;
+	u32 dataout;
+};
+
 struct gpio_bank {
 	struct list_head node;
 	unsigned long pbase;
@@ -43,7 +56,7 @@ struct gpio_bank {
 #endif
 	u32 non_wakeup_gpios;
 	u32 enabled_non_wakeup_gpios;
-
+	struct gpio_regs context;
 	u32 saved_datain;
 	u32 saved_fallingdetect;
 	u32 saved_risingdetect;
@@ -66,23 +79,6 @@ struct gpio_bank {
 	struct omap_gpio_reg_offs *regs;
 };
 
-#ifdef CONFIG_ARCH_OMAP3
-struct omap3_gpio_regs {
-	u32 irqenable1;
-	u32 irqenable2;
-	u32 wake_en;
-	u32 ctrl;
-	u32 oe;
-	u32 leveldetect0;
-	u32 leveldetect1;
-	u32 risingdetect;
-	u32 fallingdetect;
-	u32 dataout;
-};
-
-static struct omap3_gpio_regs gpio_context[OMAP34XX_NR_GPIOS];
-#endif
-
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
 
@@ -1490,33 +1486,31 @@ void omap2_gpio_resume_after_idle(void)
 void omap_gpio_save_context(void)
 {
 	struct gpio_bank *bank;
-	int i = 0;
 
 	list_for_each_entry(bank, &omap_gpio_list, node) {
-		i++;
 
 		if (!bank->loses_context)
 			continue;
 
-		gpio_context[i].irqenable1 =
+		bank->context.irqenable1 =
 			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE1);
-		gpio_context[i].irqenable2 =
+		bank->context.irqenable2 =
 			__raw_readl(bank->base + OMAP24XX_GPIO_IRQENABLE2);
-		gpio_context[i].wake_en =
+		bank->context.wake_en =
 			__raw_readl(bank->base + OMAP24XX_GPIO_WAKE_EN);
-		gpio_context[i].ctrl =
+		bank->context.ctrl =
 			__raw_readl(bank->base + OMAP24XX_GPIO_CTRL);
-		gpio_context[i].oe =
+		bank->context.oe =
 			__raw_readl(bank->base + OMAP24XX_GPIO_OE);
-		gpio_context[i].leveldetect0 =
+		bank->context.leveldetect0 =
 			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-		gpio_context[i].leveldetect1 =
+		bank->context.leveldetect1 =
 			__raw_readl(bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-		gpio_context[i].risingdetect =
+		bank->context.risingdetect =
 			__raw_readl(bank->base + OMAP24XX_GPIO_RISINGDETECT);
-		gpio_context[i].fallingdetect =
+		bank->context.fallingdetect =
 			__raw_readl(bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-		gpio_context[i].dataout =
+		bank->context.dataout =
 			__raw_readl(bank->base + OMAP24XX_GPIO_DATAOUT);
 	}
 }
@@ -1524,33 +1518,31 @@ void omap_gpio_save_context(void)
 void omap_gpio_restore_context(void)
 {
 	struct gpio_bank *bank;
-	int i = 0;
 
 	list_for_each_entry(bank, &omap_gpio_list, node) {
-		i++;
 
 		if (!bank->loses_context)
 			continue;
 
-		__raw_writel(gpio_context[i].irqenable1,
+		__raw_writel(bank->context.irqenable1,
 				bank->base + OMAP24XX_GPIO_IRQENABLE1);
-		__raw_writel(gpio_context[i].irqenable2,
+		__raw_writel(bank->context.irqenable2,
 				bank->base + OMAP24XX_GPIO_IRQENABLE2);
-		__raw_writel(gpio_context[i].wake_en,
+		__raw_writel(bank->context.wake_en,
 				bank->base + OMAP24XX_GPIO_WAKE_EN);
-		__raw_writel(gpio_context[i].ctrl,
+		__raw_writel(bank->context.ctrl,
 				bank->base + OMAP24XX_GPIO_CTRL);
-		__raw_writel(gpio_context[i].oe,
+		__raw_writel(bank->context.oe,
 				bank->base + OMAP24XX_GPIO_OE);
-		__raw_writel(gpio_context[i].leveldetect0,
+		__raw_writel(bank->context.leveldetect0,
 				bank->base + OMAP24XX_GPIO_LEVELDETECT0);
-		__raw_writel(gpio_context[i].leveldetect1,
+		__raw_writel(bank->context.leveldetect1,
 				bank->base + OMAP24XX_GPIO_LEVELDETECT1);
-		__raw_writel(gpio_context[i].risingdetect,
+		__raw_writel(bank->context.risingdetect,
 				bank->base + OMAP24XX_GPIO_RISINGDETECT);
-		__raw_writel(gpio_context[i].fallingdetect,
+		__raw_writel(bank->context.fallingdetect,
 				bank->base + OMAP24XX_GPIO_FALLINGDETECT);
-		__raw_writel(gpio_context[i].dataout,
+		__raw_writel(bank->context.dataout,
 				bank->base + OMAP24XX_GPIO_DATAOUT);
 	}
 }
Signature · 1 line
1.7.0.4
#4 lore raw

PATCH v6 4/25 gpio/omap: fix pwrdm_post_transition call sequence

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

The context lost count is modified in omap_sram_idle() path when pwrdm_post_transition() is called. But pwrdm_post_transition() is called only after omap_gpio_resume_after_idle() is called. Correct this so that context lost count is modified before calling omap_gpio_resume_after_idle().

This would be useful when OMAP GPIO save/restore context is called by the OMAP GPIO driver itself.

---
 arch/arm/mach-omap2/pm34xx.c |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)
arch/arm/mach-omap2/pm34xx.c +4 -3
index 7255d9b..1915050 100644
@@ -363,7 +363,6 @@ void omap_sram_idle(void)
 		printk(KERN_ERR "Invalid mpu state in sram_idle\n");
 		return;
 	}
-	pwrdm_pre_transition();
 
 	/* NEON control */
 	if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
@@ -386,6 +385,8 @@ void omap_sram_idle(void)
 			if (!console_trylock())
 				goto console_still_active;
 
+	pwrdm_pre_transition();
+
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
@@ -455,6 +456,8 @@ void omap_sram_idle(void)
 	}
 	omap3_intc_resume_idle();
 
+	pwrdm_post_transition();
+
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
@@ -478,8 +481,6 @@ console_still_active:
 		omap3_disable_io_chain();
 	}
 
-	pwrdm_post_transition();
-
 	clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH v6 5/25 gpio/omap: handle save/restore context in GPIO driver

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

Modify omap_gpio_prepare_for_idle() & omap_gpio_resume_after_idle() functions to handle save context & restore context respectively in the OMAP GPIO driver itself instead of calling these functions from pm specific files. For this, in gpio_prepare_for_idle(), call *_get_context_loss_count() and in gpio_resume_after_idle() call it again. If the count is different, do restore context. The workaround_enabled flag is no more required and is removed.

---
 arch/arm/mach-omap2/gpio.c             |    5 +-
 arch/arm/mach-omap2/pm34xx.c           |   14 ----
 arch/arm/plat-omap/include/plat/gpio.h |    5 +-
 drivers/gpio/gpio-omap.c               |  131 ++++++++++++++------------------
 4 files changed, 65 insertions(+), 90 deletions(-)
arch/arm/mach-omap2/gpio.c +4 -1
index 9f3a007..6c6b1a7 100644
@@ -23,6 +23,7 @@
 
 #include <plat/omap_hwmod.h>
 #include <plat/omap_device.h>
+#include <plat/omap-pm.h>
 
 #include "powerdomain.h"
 
@@ -63,7 +64,9 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 	pdata->bank_width = dev_attr->bank_width;
 	pdata->dbck_flag = dev_attr->dbck_flag;
 	pdata->virtual_irq_start = IH_GPIO_BASE + 32 * (id - 1);
-
+#ifdef CONFIG_PM
+	pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count;
+#endif
 	pdata->regs = kzalloc(sizeof(struct omap_gpio_reg_offs), GFP_KERNEL);
 	if (!pdata) {
 		pr_err("gpio%d: Memory allocation failed\n", id);
arch/arm/mach-omap2/pm34xx.c +0 -14
index 1915050..b33cf3d 100644
@@ -85,16 +85,6 @@ static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
 static struct powerdomain *cam_pwrdm;
 
-static inline void omap3_per_save_context(void)
-{
-	omap_gpio_save_context();
-}
-
-static inline void omap3_per_restore_context(void)
-{
-	omap_gpio_restore_context();
-}
-
 static void omap3_enable_io_chain(void)
 {
 	int timeout = 0;
@@ -393,8 +383,6 @@ void omap_sram_idle(void)
 		omap_uart_prepare_idle(2);
 		omap_uart_prepare_idle(3);
 		omap2_gpio_prepare_for_idle(per_going_off);
-		if (per_next_state == PWRDM_POWER_OFF)
-				omap3_per_save_context();
 	}
 
 	/* CORE */
@@ -462,8 +450,6 @@ void omap_sram_idle(void)
 	if (per_next_state < PWRDM_POWER_ON) {
 		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
 		omap2_gpio_resume_after_idle();
-		if (per_prev_state == PWRDM_POWER_OFF)
-			omap3_per_restore_context();
 		omap_uart_resume_idle(2);
 		omap_uart_resume_idle(3);
 	}
arch/arm/plat-omap/include/plat/gpio.h +3 -2
index 58d0bf2..2c06e43 100644
@@ -201,14 +201,15 @@ struct omap_gpio_platform_data {
 	bool loses_context;	/* whether the bank would ever lose context */
 
 	struct omap_gpio_reg_offs *regs;
+
+	/* Return context loss count due to PM states changing */
+	u32 (*get_context_loss_count)(struct device *dev);
 };
 
 extern void omap2_gpio_prepare_for_idle(int off_mode);
 extern void omap2_gpio_resume_after_idle(void);
 extern void omap_set_gpio_debounce(int gpio, int enable);
 extern void omap_set_gpio_debounce_time(int gpio, int enable);
-extern void omap_gpio_save_context(void);
-extern void omap_gpio_restore_context(void);
 /*-------------------------------------------------------------------------*/
 
 /* Wrappers for "new style" GPIO calls, using the new infrastructure
drivers/gpio/gpio-omap.c +58 -73

192 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#6 lore raw

PATCH v6 6/25 gpio/omap: make non-wakeup GPIO part of pdata

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

Non-wakeup GPIOs are available only in OMAP2. Avoid cpu_is checks by making non_wakeup_gpios as part of pdata.

---
 arch/arm/mach-omap2/gpio.c             |    8 ++++++++
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |    8 +-------
 3 files changed, 10 insertions(+), 7 deletions(-)
arch/arm/mach-omap2/gpio.c +8 -0
index 6c6b1a7..a430fb1 100644
@@ -75,6 +75,14 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 
 	switch (oh->class->rev) {
 	case 0:
+		if (id == 1)
+			/* non-wakeup GPIO pins for OMAP2 Bank1 */
+			pdata->non_wakeup_gpios = 0xe203ffc0;
+		else if (id == 2)
+			/* non-wakeup GPIO pins for OMAP2 Bank2 */
+			pdata->non_wakeup_gpios = 0x08700040;
+		/* fall through */
+
 	case 1:
 		pdata->bank_type = METHOD_GPIO_24XX;
 		pdata->regs->revision = OMAP24XX_GPIO_REVISION;
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index 2c06e43..a93adeb 100644
@@ -199,6 +199,7 @@ struct omap_gpio_platform_data {
 	int bank_stride;	/* Only needed for omap1 MPUIO */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
 	bool loses_context;	/* whether the bank would ever lose context */
+	u32 non_wakeup_gpios;
 
 	struct omap_gpio_reg_offs *regs;
 
drivers/gpio/gpio-omap.c +1 -7
index d114759..69271c4 100644
@@ -1017,13 +1017,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
 
 			/* Initialize interface clk ungated, module enabled */
 			__raw_writel(0, bank->base + OMAP24XX_GPIO_CTRL);
-		} else if (cpu_is_omap24xx()) {
-			static const u32 non_wakeup_gpios[] = {
-				0xe203ffc0, 0x08700040
-			};
-			if (bank->id < ARRAY_SIZE(non_wakeup_gpios))
-				bank->non_wakeup_gpios =
-						non_wakeup_gpios[bank->id];
 		}
 	} else if (cpu_class_is_omap1()) {
 		if (bank_is_mpuio(bank)) {
@@ -1171,6 +1164,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	bank->dbck_flag = pdata->dbck_flag;
 	bank->stride = pdata->bank_stride;
 	bank->width = pdata->bank_width;
+	bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
 	bank->loses_context = pdata->loses_context;
 	bank->get_context_loss_count = pdata->get_context_loss_count;
 	bank->regs = pdata->regs;
Signature · 1 line
1.7.0.4
#7 lore raw

PATCH v6 7/25 gpio/omap: avoid cpu checks during module ena/disable

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

Remove cpu-is checks while enabling/disabling OMAP GPIO module during a gpio request/free.

---
 arch/arm/mach-omap2/gpio.c             |    2 +
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |   53 ++++++++++++++------------------
 3 files changed, 26 insertions(+), 30 deletions(-)
arch/arm/mach-omap2/gpio.c +2 -0
index a430fb1..72a640d 100644
@@ -98,6 +98,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
 		pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
 		pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
+		pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
 		break;
 	case 2:
 		pdata->bank_type = METHOD_GPIO_44XX;
@@ -114,6 +115,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
 		pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
 		pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
+		pdata->regs->ctrl = OMAP4_GPIO_CTRL;
 		break;
 	default:
 		WARN(1, "Invalid gpio bank_type\n");
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index a93adeb..eaa6de3 100644
@@ -188,6 +188,7 @@ struct omap_gpio_reg_offs {
 	u16 clr_irqenable;
 	u16 debounce;
 	u16 debounce_en;
+	u16 ctrl;
 
 	bool irqenable_inv;
 };
drivers/gpio/gpio-omap.c +23 -30

73 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#8 lore raw

PATCH v6 8/25 gpio/omap: further cleanup using wkup_en register

In reply to Tarun Kanti DebBarma

Wakeup enable register offset initialized according to OMAP versions during device registration. Use this to avoid version checks. Starting with OMAP4, legacy registers should not be used in combination with the updated regsiters. Use wkup_en register consistently for all SoCs wherever applicable.

---
 arch/arm/mach-omap1/gpio16xx.c         |    1 +
 arch/arm/mach-omap2/gpio.c             |    2 +
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |  108 ++++++--------------------------
 4 files changed, 23 insertions(+), 89 deletions(-)
arch/arm/mach-omap1/gpio16xx.c +1 -0
index df4bb44..1eb47e2 100644
@@ -89,6 +89,7 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
 	.irqenable	= OMAP1610_GPIO_IRQENABLE1,
 	.set_irqenable	= OMAP1610_GPIO_SET_IRQENABLE1,
 	.clr_irqenable	= OMAP1610_GPIO_CLEAR_IRQENABLE1,
+	.wkup_en	= OMAP1610_GPIO_WAKEUPENABLE,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
arch/arm/mach-omap2/gpio.c +2 -0
index 72a640d..b1364b6 100644
@@ -99,6 +99,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
 		pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
 		pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
+		pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN;
 		break;
 	case 2:
 		pdata->bank_type = METHOD_GPIO_44XX;
@@ -116,6 +117,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
 		pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
 		pdata->regs->ctrl = OMAP4_GPIO_CTRL;
+		pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0;
 		break;
 	default:
 		WARN(1, "Invalid gpio bank_type\n");
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index eaa6de3..7ea1608 100644
@@ -189,6 +189,7 @@ struct omap_gpio_reg_offs {
 	u16 debounce;
 	u16 debounce_en;
 	u16 ctrl;
+	u16 wkup_en;
 
 	bool irqenable_inv;
 };
drivers/gpio/gpio-omap.c +19 -89

172 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#9 lore raw

PATCH v6 9/25 gpio/omap: use level/edge detect reg offsets

In reply to Tarun Kanti DebBarma

By adding level and edge detection register offsets and then initializing them correctly according to OMAP versions during device registrations we can now remove lot of revision checks in these functions.

---
 arch/arm/mach-omap2/gpio.c             |    8 ++
 arch/arm/plat-omap/include/plat/gpio.h |    4 +
 drivers/gpio/gpio-omap.c               |  118 ++++++++++----------------------
 3 files changed, 48 insertions(+), 82 deletions(-)
arch/arm/mach-omap2/gpio.c +8 -0
index b1364b6..06fa913 100644
@@ -100,6 +100,10 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->debounce_en = OMAP24XX_GPIO_DEBOUNCE_EN;
 		pdata->regs->ctrl = OMAP24XX_GPIO_CTRL;
 		pdata->regs->wkup_en = OMAP24XX_GPIO_WAKE_EN;
+		pdata->regs->leveldetect0 = OMAP24XX_GPIO_LEVELDETECT0;
+		pdata->regs->leveldetect1 = OMAP24XX_GPIO_LEVELDETECT1;
+		pdata->regs->risingdetect = OMAP24XX_GPIO_RISINGDETECT;
+		pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;
 		break;
 	case 2:
 		pdata->bank_type = METHOD_GPIO_44XX;
@@ -118,6 +122,10 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->debounce_en = OMAP4_GPIO_DEBOUNCENABLE;
 		pdata->regs->ctrl = OMAP4_GPIO_CTRL;
 		pdata->regs->wkup_en = OMAP4_GPIO_IRQWAKEN0;
+		pdata->regs->leveldetect0 = OMAP4_GPIO_LEVELDETECT0;
+		pdata->regs->leveldetect1 = OMAP4_GPIO_LEVELDETECT1;
+		pdata->regs->risingdetect = OMAP4_GPIO_RISINGDETECT;
+		pdata->regs->fallingdetect = OMAP4_GPIO_FALLINGDETECT;
 		break;
 	default:
 		WARN(1, "Invalid gpio bank_type\n");
arch/arm/plat-omap/include/plat/gpio.h +4 -0
index 7ea1608..9590532 100644
@@ -190,6 +190,10 @@ struct omap_gpio_reg_offs {
 	u16 debounce_en;
 	u16 ctrl;
 	u16 wkup_en;
+	u16 leveldetect0;
+	u16 leveldetect1;
+	u16 risingdetect;
+	u16 fallingdetect;
 
 	bool irqenable_inv;
 };
drivers/gpio/gpio-omap.c +36 -82

168 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#10 lore raw

PATCH v6 10/25 gpio/omap: remove hardcoded offsets in context save/restore

In reply to Tarun Kanti DebBarma

It is not required to use hard-coded offsets any more in context save and restore functions and instead use the generic offsets which have been correctly initialized during device registration.

---
 arch/arm/mach-omap2/gpio.c             |    2 +
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |   41 ++++++++++++++-----------------
 3 files changed, 22 insertions(+), 22 deletions(-)
arch/arm/mach-omap2/gpio.c +2 -0
index 06fa913..5ce695c 100644
@@ -94,6 +94,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->irqstatus = OMAP24XX_GPIO_IRQSTATUS1;
 		pdata->regs->irqstatus2 = OMAP24XX_GPIO_IRQSTATUS2;
 		pdata->regs->irqenable = OMAP24XX_GPIO_IRQENABLE1;
+		pdata->regs->irqenable2 = OMAP24XX_GPIO_IRQENABLE2;
 		pdata->regs->set_irqenable = OMAP24XX_GPIO_SETIRQENABLE1;
 		pdata->regs->clr_irqenable = OMAP24XX_GPIO_CLEARIRQENABLE1;
 		pdata->regs->debounce = OMAP24XX_GPIO_DEBOUNCE_VAL;
@@ -116,6 +117,7 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->irqstatus = OMAP4_GPIO_IRQSTATUS0;
 		pdata->regs->irqstatus2 = OMAP4_GPIO_IRQSTATUS1;
 		pdata->regs->irqenable = OMAP4_GPIO_IRQSTATUSSET0;
+		pdata->regs->irqenable2 = OMAP4_GPIO_IRQSTATUSSET1;
 		pdata->regs->set_irqenable = OMAP4_GPIO_IRQSTATUSSET0;
 		pdata->regs->clr_irqenable = OMAP4_GPIO_IRQSTATUSCLR0;
 		pdata->regs->debounce = OMAP4_GPIO_DEBOUNCINGTIME;
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index 9590532..61865b4 100644
@@ -184,6 +184,7 @@ struct omap_gpio_reg_offs {
 	u16 irqstatus;
 	u16 irqstatus2;
 	u16 irqenable;
+	u16 irqenable2;
 	u16 set_irqenable;
 	u16 clr_irqenable;
 	u16 debounce;
drivers/gpio/gpio-omap.c +19 -22

64 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#11 lore raw

PATCH v6 11/25 gpio/omap: cleanup set_gpio_triggering function

In reply to Tarun Kanti DebBarma

Getting rid of ifdefs within the function by adding register offset intctrl and associating OMAPXXXX_GPIO_INT_CONTROL in respective SoC specific files. Also, use wkup_status register consistently instead of referring to wakeup clear and wakeup set register offsets.

---
 arch/arm/mach-omap1/gpio15xx.c         |    2 +
 arch/arm/mach-omap1/gpio16xx.c         |    3 +
 arch/arm/mach-omap1/gpio7xx.c          |    2 +
 arch/arm/plat-omap/include/plat/gpio.h |    3 +
 drivers/gpio/gpio-omap.c               |  148 ++++++++------------------------
 5 files changed, 46 insertions(+), 112 deletions(-)
arch/arm/mach-omap1/gpio15xx.c +2 -0
index f8c15ea..2adfece 100644
@@ -42,6 +42,7 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
 	.irqstatus	= OMAP_MPUIO_GPIO_INT,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
@@ -83,6 +84,7 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
 	.irqstatus	= OMAP1510_GPIO_INT_STATUS,
 	.irqenable	= OMAP1510_GPIO_INT_MASK,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP1510_GPIO_INT_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
arch/arm/mach-omap1/gpio16xx.c +3 -0
index 1eb47e2..46bb57a 100644
@@ -45,6 +45,7 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
 	.irqstatus	= OMAP_MPUIO_GPIO_INT,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
@@ -90,6 +91,8 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
 	.set_irqenable	= OMAP1610_GPIO_SET_IRQENABLE1,
 	.clr_irqenable	= OMAP1610_GPIO_CLEAR_IRQENABLE1,
 	.wkup_en	= OMAP1610_GPIO_WAKEUPENABLE,
+	.edgectrl1	= OMAP1610_GPIO_EDGE_CTRL1,
+	.edgectrl2	= OMAP1610_GPIO_EDGE_CTRL2,
 };
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
arch/arm/mach-omap1/gpio7xx.c +2 -0
index 923eaa1..207a23c 100644
@@ -47,6 +47,7 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
 	.irqstatus	= OMAP_MPUIO_GPIO_INT / 2,
 	.irqenable	= OMAP_MPUIO_GPIO_MASKIT / 2,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP_MPUIO_GPIO_INT_EDGE >> 1,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
@@ -88,6 +89,7 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
 	.irqstatus	= OMAP7XX_GPIO_INT_STATUS,
 	.irqenable	= OMAP7XX_GPIO_INT_MASK,
 	.irqenable_inv	= true,
+	.irqctrl	= OMAP7XX_GPIO_INT_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
arch/arm/plat-omap/include/plat/gpio.h +3 -0
index 61865b4..92a6262 100644
@@ -195,6 +195,9 @@ struct omap_gpio_reg_offs {
 	u16 leveldetect1;
 	u16 risingdetect;
 	u16 fallingdetect;
+	u16 irqctrl;
+	u16 edgectrl1;
+	u16 edgectrl2;
 
 	bool irqenable_inv;
 };
drivers/gpio/gpio-omap.c +36 -112

201 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#12 lore raw

PATCH v6 12/25 gpio/omap: cleanup omap_gpio_mod_init function

In reply to Tarun Kanti DebBarma

With register offsets now defined for respective OMAP versions we can get rid of cpu_class_* checks. This function now has common initialization code for all OMAP versions. Initialization specific to OMAP16xx has been moved within omap16xx_gpio_init().

---
 arch/arm/mach-omap1/gpio16xx.c |   35 +++++++++++++++++++-
 drivers/gpio/gpio-omap.c       |   71 +++++++++------------------------------
 2 files changed, 51 insertions(+), 55 deletions(-)
arch/arm/mach-omap1/gpio16xx.c +34 -1
index 46bb57a..86ac415 100644
@@ -24,6 +24,9 @@
 #define OMAP1610_GPIO4_BASE		0xfffbbc00
 #define OMAP1_MPUIO_VBASE		OMAP1_MPUIO_BASE
 
+/* smart idle, enable wakeup */
+#define SYSCONFIG_WORD			0x14
+
 /* mpu gpio */
 static struct __initdata resource omap16xx_mpu_gpio_resources[] = {
 	{
@@ -218,12 +221,42 @@ static struct __initdata platform_device * omap16xx_gpio_dev[] = {
 static int __init omap16xx_gpio_init(void)
 {
 	int i;
+	void __iomem *base;
+	struct resource *res;
+	struct platform_device *pdev;
+	struct omap_gpio_platform_data *pdata;
 
 	if (!cpu_is_omap16xx())
 		return -EINVAL;
 
-	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++)
+	for (i = 0; i < ARRAY_SIZE(omap16xx_gpio_dev); i++) {
+		pdev = omap16xx_gpio_dev[i];
+		pdata = pdev->dev.platform_data;
+
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+		if (unlikely(!res)) {
+			dev_err(&pdev->dev, "Invalid mem resource.\n");
+			return -ENODEV;
+		}
+
+		base = ioremap(res->start, resource_size(res));
+		if (unlikely(!base)) {
+			dev_err(&pdev->dev, "ioremap failed.\n");
+			return -ENOMEM;
+		}
+
+		__raw_writel(SYSCONFIG_WORD, base + OMAP1610_GPIO_SYSCONFIG);
+		iounmap(base);
+
+		/*
+		 * Enable system clock for GPIO module.
+		 * The CAM_CLK_CTRL *is* really the right place.
+		 */
+		omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04,
+					ULPD_CAM_CLK_CTRL);
+
 		platform_device_register(omap16xx_gpio_dev[i]);
+	}
 
 	return 0;
 }
drivers/gpio/gpio-omap.c +17 -54

99 lines not on this page · raw message

Signature · 1 line
1.7.0.4
#13 lore raw

PATCH v6 13/25 gpio/omap: use pinctrl offset instead of macro

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

Use regs->pinctrl field instead of using the macro OMAP1510_GPIO_PIN_CONTROL

---
 arch/arm/mach-omap1/gpio15xx.c         |    1 +
 arch/arm/plat-omap/include/plat/gpio.h |    1 +
 drivers/gpio/gpio-omap.c               |    8 +++-----
 3 files changed, 5 insertions(+), 5 deletions(-)
arch/arm/mach-omap1/gpio15xx.c +1 -0
index 2adfece..950e467 100644
@@ -85,6 +85,7 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
 	.irqenable	= OMAP1510_GPIO_INT_MASK,
 	.irqenable_inv	= true,
 	.irqctrl	= OMAP1510_GPIO_INT_CONTROL,
+	.pinctrl	= OMAP1510_GPIO_PIN_CONTROL,
 };
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
arch/arm/plat-omap/include/plat/gpio.h +1 -0
index 92a6262..a4e5ef3 100644
@@ -198,6 +198,7 @@ struct omap_gpio_reg_offs {
 	u16 irqctrl;
 	u16 edgectrl1;
 	u16 edgectrl2;
+	u16 pinctrl;
 
 	bool irqenable_inv;
 };
drivers/gpio/gpio-omap.c +3 -5
index fa2fb4f..e2a8b09 100644
@@ -481,15 +481,13 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 	 */
 	_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE);
 
-#ifdef CONFIG_ARCH_OMAP15XX
-	if (bank->method == METHOD_GPIO_1510) {
-		void __iomem *reg;
+	if (bank->regs->pinctrl) {
+		void __iomem *reg = bank->base + bank->regs->pinctrl;
 
 		/* Claim the pin for MPU */
-		reg = bank->base + OMAP1510_GPIO_PIN_CONTROL;
 		__raw_writel(__raw_readl(reg) | (1 << offset), reg);
 	}
-#endif
+
 	if (bank->regs->ctrl && !bank->mod_usage) {
 		void __iomem *reg = bank->base + bank->regs->ctrl;
 		u32 ctrl;
Signature · 1 line
1.7.0.4
#14 lore raw

PATCH v6 14/25 gpio/omap: remove unnecessary bit-masking for read access

In reply to Tarun Kanti DebBarma

Remove un-necessary bit masking. Since the register are 4 byte aligned and readl would work as is. The 'enabled' mask is already taking care to mask for bank width.

---
 drivers/gpio/gpio-omap.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/gpio/gpio-omap.c +0 -2
index e2a8b09..08c7991 100644
@@ -567,8 +567,6 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 		enabled = _get_gpio_irqbank_mask(bank);
 		isr_saved = isr = __raw_readl(isr_reg) & enabled;
 
-		if (cpu_is_omap15xx() && (bank->method == METHOD_MPUIO))
-			isr &= 0x0000ffff;
 
 		if (bank->level_mask)
 			level_mask = bank->level_mask & enabled;
Signature · 1 line
1.7.0.4
#15 lore raw

PATCH v6 15/25 gpio/omap: remove bank->method & METHOD_* macros

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

The only bank->type (method) used in the OMAP GPIO driver is MPUIO type as they need to be handled separately. Identify the same using a flag and remove all METHOD_* macros.

mpuio_init() function is defined under #ifdefs. It is required only in case of MPUIO bank type and only when PM operations are supported by it. This is applicable only in case of OMAP16xx SoC's MPUIO GPIO bank type. For all the other cases it is a dummy function. Hence clean up the same and remove all the OMAP SoC specific #ifdefs.

---
 arch/arm/mach-omap1/gpio15xx.c         |    3 +-
 arch/arm/mach-omap1/gpio16xx.c         |    6 +----
 arch/arm/mach-omap1/gpio7xx.c          |    8 +------
 arch/arm/mach-omap2/gpio.c             |    2 -
 arch/arm/plat-omap/include/plat/gpio.h |    8 +------
 drivers/gpio/gpio-omap.c               |   38 +++++--------------------------
 6 files changed, 10 insertions(+), 55 deletions(-)
arch/arm/mach-omap1/gpio15xx.c +1 -2
index 950e467..634903e 100644
@@ -47,7 +47,7 @@ static struct omap_gpio_reg_offs omap15xx_mpuio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
+	.is_mpuio		= true,
 	.bank_width		= 16,
 	.bank_stride		= 1,
 	.regs			= &omap15xx_mpuio_regs,
@@ -90,7 +90,6 @@ static struct omap_gpio_reg_offs omap15xx_gpio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_1510,
 	.bank_width		= 16,
 	.regs                   = &omap15xx_gpio_regs,
 };
arch/arm/mach-omap1/gpio16xx.c +1 -5
index 86ac415..1c5f90e 100644
@@ -53,7 +53,7 @@ static struct omap_gpio_reg_offs omap16xx_mpuio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
+	.is_mpuio		= true,
 	.bank_width		= 16,
 	.bank_stride		= 1,
 	.regs                   = &omap16xx_mpuio_regs,
@@ -100,7 +100,6 @@ static struct omap_gpio_reg_offs omap16xx_gpio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -130,7 +129,6 @@ static struct __initdata resource omap16xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 16,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -160,7 +158,6 @@ static struct __initdata resource omap16xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 32,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
@@ -190,7 +187,6 @@ static struct __initdata resource omap16xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 48,
-	.bank_type		= METHOD_GPIO_1610,
 	.bank_width		= 16,
 	.regs                   = &omap16xx_gpio_regs,
 };
arch/arm/mach-omap1/gpio7xx.c +1 -7
index 207a23c..433491c 100644
@@ -52,8 +52,8 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_type		= METHOD_MPUIO,
 	.bank_width		= 32,
+	.is_mpuio		= true,
 	.bank_stride		= 2,
 	.regs                   = &omap7xx_mpuio_regs,
 };
@@ -94,7 +94,6 @@ static struct omap_gpio_reg_offs omap7xx_gpio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = {
 	.virtual_irq_start	= IH_GPIO_BASE,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -124,7 +123,6 @@ static struct __initdata resource omap7xx_gpio2_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 32,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -154,7 +152,6 @@ static struct __initdata resource omap7xx_gpio3_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 64,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -184,7 +181,6 @@ static struct __initdata resource omap7xx_gpio4_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 96,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -214,7 +210,6 @@ static struct __initdata resource omap7xx_gpio5_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 128,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
@@ -244,7 +239,6 @@ static struct __initdata resource omap7xx_gpio6_resources[] = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = {
 	.virtual_irq_start	= IH_GPIO_BASE + 160,
-	.bank_type		= METHOD_GPIO_7XX,
 	.bank_width		= 32,
 	.regs			= &omap7xx_gpio_regs,
 };
arch/arm/mach-omap2/gpio.c +0 -2
index 5ce695c..d865033 100644
@@ -84,7 +84,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		/* fall through */
 
 	case 1:
-		pdata->bank_type = METHOD_GPIO_24XX;
 		pdata->regs->revision = OMAP24XX_GPIO_REVISION;
 		pdata->regs->direction = OMAP24XX_GPIO_OE;
 		pdata->regs->datain = OMAP24XX_GPIO_DATAIN;
@@ -107,7 +106,6 @@ static int omap2_gpio_dev_init(struct omap_hwmod *oh, void *unused)
 		pdata->regs->fallingdetect = OMAP24XX_GPIO_FALLINGDETECT;
 		break;
 	case 2:
-		pdata->bank_type = METHOD_GPIO_44XX;
 		pdata->regs->revision = OMAP4_GPIO_REVISION;
 		pdata->regs->direction = OMAP4_GPIO_OE;
 		pdata->regs->datain = OMAP4_GPIO_DATAIN;
arch/arm/plat-omap/include/plat/gpio.h +1 -7
index a4e5ef3..c63b2ad 100644
@@ -162,13 +162,6 @@
 				 IH_MPUIO_BASE + ((nr) & 0x0f) : \
 				 IH_GPIO_BASE + (nr))
 
-#define METHOD_MPUIO		0
-#define METHOD_GPIO_1510	1
-#define METHOD_GPIO_1610	2
-#define METHOD_GPIO_7XX		3
-#define METHOD_GPIO_24XX	5
-#define METHOD_GPIO_44XX	6
-
 struct omap_gpio_dev_attr {
 	int bank_width;		/* GPIO bank width */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
@@ -210,6 +203,7 @@ struct omap_gpio_platform_data {
 	int bank_stride;	/* Only needed for omap1 MPUIO */
 	bool dbck_flag;		/* dbck required or not - True for OMAP3&4 */
 	bool loses_context;	/* whether the bank would ever lose context */
+	bool is_mpuio;		/* whether the bank is of type MPUIO */
 	u32 non_wakeup_gpios;
 
 	struct omap_gpio_reg_offs *regs;
drivers/gpio/gpio-omap.c +6 -32
index 08c7991..6e7399c 100644
@@ -49,7 +49,6 @@ struct gpio_bank {
 	void __iomem *base;
 	u16 irq;
 	u16 virtual_irq_start;
-	int method;
 	u32 suspend_wakeup;
 	u32 saved_wakeup;
 	u32 non_wakeup_gpios;
@@ -66,6 +65,7 @@ struct gpio_bank {
 	u32 mod_usage;
 	u32 dbck_enable_mask;
 	struct device *dev;
+	bool is_mpuio;
 	bool dbck_flag;
 	bool loses_context;
 	int stride;
@@ -685,14 +685,6 @@ static struct irq_chip gpio_irq_chip = {
 
 /*---------------------------------------------------------------------*/
 
-#ifdef CONFIG_ARCH_OMAP1
-
-#define bank_is_mpuio(bank)	((bank)->method == METHOD_MPUIO)
-
-#ifdef CONFIG_ARCH_OMAP16XX
-
-#include <linux/platform_device.h>
-
 static int omap_mpuio_suspend_noirq(struct device *dev)
 {
 	struct platform_device *pdev = to_platform_device(dev);
@@ -754,23 +746,8 @@ static inline void mpuio_init(struct gpio_bank *bank)
 		(void) platform_device_register(&omap_mpuio_device);
 }
 
-#else
-static inline void mpuio_init(struct gpio_bank *bank) {}
-#endif	/* 16xx */
-
-#else
-
-#define bank_is_mpuio(bank)	0
-static inline void mpuio_init(struct gpio_bank *bank) {}
-
-#endif
-
 /*---------------------------------------------------------------------*/
 
-/* REVISIT these are stupid implementations!  replace by ones that
- * don't switch on METHOD_* and which mostly avoid spinlocks
- */
-
 static int gpio_input(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank;
@@ -891,7 +868,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
 	if (bank->width == 16)
 		l = 0xffff;
 
-	if (bank_is_mpuio(bank)) {
+	if (bank->is_mpuio) {
 		__raw_writel(l, bank->base + bank->regs->irqenable);
 		return;
 	}
@@ -932,7 +909,6 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 	int j;
 	static int gpio;
 
-	bank->mod_usage = 0;
 	/*
 	 * REVISIT eventually switch from OMAP-specific gpio structs
 	 * over to the generic ones
@@ -945,12 +921,10 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 	bank->chip.set_debounce = gpio_debounce;
 	bank->chip.set = gpio_set;
 	bank->chip.to_irq = gpio_2irq;
-	if (bank_is_mpuio(bank)) {
+	if (bank->is_mpuio) {
 		bank->chip.label = "mpuio";
-#ifdef CONFIG_ARCH_OMAP16XX
 		if (bank->regs->wkup_en)
 			bank->chip.dev = &omap_mpuio_device.dev;
-#endif
 		bank->chip.base = OMAP_MPUIO(0);
 	} else {
 		bank->chip.label = "gpio";
@@ -965,7 +939,7 @@ static void __devinit omap_gpio_chip_init(struct gpio_bank *bank)
 		     j < bank->virtual_irq_start + bank->width; j++) {
 		irq_set_lockdep_class(j, &gpio_lock_class);
 		irq_set_chip_data(j, bank);
-		if (bank_is_mpuio(bank)) {
+		if (bank->is_mpuio) {
 			omap_mpuio_alloc_gc(bank, j, bank->width);
 		} else {
 			irq_set_chip(j, &gpio_irq_chip);
@@ -1009,11 +983,11 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 
 	pdata = pdev->dev.platform_data;
 	bank->virtual_irq_start = pdata->virtual_irq_start;
-	bank->method = pdata->bank_type;
 	bank->dev = &pdev->dev;
 	bank->dbck_flag = pdata->dbck_flag;
 	bank->stride = pdata->bank_stride;
 	bank->width = pdata->bank_width;
+	bank->is_mpuio = pdata->is_mpuio;
 	bank->non_wakeup_gpios = pdata->non_wakeup_gpios;
 	bank->loses_context = pdata->loses_context;
 	bank->get_context_loss_count = pdata->get_context_loss_count;
@@ -1046,7 +1020,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	pm_runtime_enable(bank->dev);
 	pm_runtime_get_sync(bank->dev);
 
-	if (bank_is_mpuio(bank))
+	if (bank->is_mpuio)
 		mpuio_init(bank);
 
 	omap_gpio_mod_init(bank);
Signature · 1 line
1.7.0.4
#16 lore raw

PATCH v6 16/25 gpio/omap: fix bankwidth for OMAP7xx MPUIO

In reply to Tarun Kanti DebBarma

From: Charulatha V <[email protected]>

In all OMAP1 SoCs, the MPUIO bank width is 16 bits. But, in OMAP7xx, it is wrongly initialised to 32. Fix this.

---
 arch/arm/mach-omap1/gpio7xx.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
arch/arm/mach-omap1/gpio7xx.c +1 -1
index 433491c..4771d6b 100644
@@ -52,8 +52,8 @@ static struct omap_gpio_reg_offs omap7xx_mpuio_regs = {
 
 static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = {
 	.virtual_irq_start	= IH_MPUIO_BASE,
-	.bank_width		= 32,
 	.is_mpuio		= true,
+	.bank_width		= 16,
 	.bank_stride		= 2,
 	.regs                   = &omap7xx_mpuio_regs,
 };
Signature · 1 line
1.7.0.4
#17 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

In reply to Tarun Kanti DebBarma

Call runtime pm APIs pm_runtime_get_sync() and pm_runtime_put_sync() for enabling/disabling clocks appropriately. Remove syscore_ops and instead use dev_pm_ops now.

---
 drivers/gpio/gpio-omap.c |   89 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 67 insertions(+), 22 deletions(-)
drivers/gpio/gpio-omap.c +67 -22
index 6e7399c..f36931a 100644
@@ -79,6 +79,8 @@ struct gpio_bank {
 	struct omap_gpio_reg_offs *regs;
 };
 
+static void omap_gpio_mod_init(struct gpio_bank *bank);
+
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
 #define GPIO_MOD_CTRL_BIT	BIT(0)
@@ -476,6 +478,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 
 	spin_lock_irqsave(&bank->lock, flags);
 
+	/*
+	 * If this is the first gpio_request for the bank,
+	 * enable the bank module.
+	 */
+	if (!bank->mod_usage)
+		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_get_sync failed\n",
+					__func__, bank->id);
+			spin_unlock_irqrestore(&bank->lock, flags);
+			return -EINVAL;
+		}
+
 	/* Set trigger to none. You need to enable the desired trigger with
 	 * request_irq() or set_irq_type().
 	 */
@@ -530,6 +545,19 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 	}
 
 	_reset_gpio(bank, bank->chip.base + offset);
+
+	/*
+	 * If this is the last gpio to be freed in the bank,
+	 * disable the bank module.
+	 */
+	if (!bank->mod_usage) {
+		if (IS_ERR_VALUE(pm_runtime_put_sync(bank->dev) < 0)) {
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_put_sync failed\n",
+					__func__, bank->id);
+		}
+	}
+
 	spin_unlock_irqrestore(&bank->lock, flags);
 }
 
@@ -556,6 +584,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
 	bank = irq_get_handler_data(irq);
 	isr_reg = bank->base + bank->regs->irqstatus;
+	pm_runtime_get_sync(bank->dev);
 
 	if (WARN_ON(!isr_reg))
 		goto exit;
@@ -617,6 +646,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 exit:
 	if (!unmasked)
 		chained_irq_exit(chip, desc);
+	pm_runtime_put_sync_suspend(bank->dev);
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
@@ -1018,7 +1048,13 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	}
 
 	pm_runtime_enable(bank->dev);
-	pm_runtime_get_sync(bank->dev);
+	pm_runtime_irq_safe(bank->dev);
+	if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {
+		dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
+				"failed\n", __func__, bank->id);
+		iounmap(bank->base);
+		return -EINVAL;
+	}
 
 	if (bank->is_mpuio)
 		mpuio_init(bank);
@@ -1027,6 +1063,13 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	omap_gpio_chip_init(bank);
 	omap_gpio_show_rev(bank);
 
+	if (IS_ERR_VALUE(pm_runtime_put_sync(bank->dev) < 0)) {
+		dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
+				"failed\n", __func__, bank->id);
+		iounmap(bank->base);
+		return -EINVAL;
+	}
+
 	list_add_tail(&bank->node, &omap_gpio_list);
 
 	return ret;
@@ -1037,7 +1080,7 @@ err_exit:
 	return ret;
 }
 
-static int omap_gpio_suspend(void)
+static int omap_gpio_suspend(struct device *dev)
 {
 	struct gpio_bank *bank;
 
@@ -1055,12 +1098,13 @@ static int omap_gpio_suspend(void)
 		bank->saved_wakeup = __raw_readl(wake_status);
 		MOD_REG_BIT(bank->regs->wkup_en, bank->suspend_wakeup, 1);
 		spin_unlock_irqrestore(&bank->lock, flags);
+		pm_runtime_put_sync(dev);
 	}
 
 	return 0;
 }
 
-static void omap_gpio_resume(void)
+static int omap_gpio_resume(struct device *dev)
 {
 	struct gpio_bank *bank;
 
@@ -1069,18 +1113,16 @@ static void omap_gpio_resume(void)
 		unsigned long flags;
 
 		if (!bank->regs->wkup_en)
-			return;
+			return 0;
 
+		pm_runtime_get_sync(dev);
 		spin_lock_irqsave(&bank->lock, flags);
 		MOD_REG_BIT(bank->regs->wkup_en, bank->saved_wakeup, 1);
 		spin_unlock_irqrestore(&bank->lock, flags);
 	}
-}
 
-static struct syscore_ops omap_gpio_syscore_ops = {
-	.suspend	= omap_gpio_suspend,
-	.resume		= omap_gpio_resume,
-};
+	return 0;
+}
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
 
@@ -1104,6 +1146,11 @@ void omap2_gpio_prepare_for_idle(int off_mode)
 		if (!off_mode)
 			continue;
 
+		if (IS_ERR_VALUE(pm_runtime_put_sync_suspend(bank->dev) < 0))
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_put_sync_suspend failed\n",
+					__func__, bank->id);
+
 		/* If going to OFF, remove triggering for all
 		 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
 		 * generated.  See OMAP2420 Errata item 1.101. */
@@ -1144,6 +1191,11 @@ void omap2_gpio_resume_after_idle(void)
 		if (!bank->loses_context)
 			continue;
 
+		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0))
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_get_sync failed\n",
+					__func__, bank->id);
+
 		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 			clk_enable(bank->dbck);
 
@@ -1258,10 +1310,16 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 }
 #endif
 
+static const struct dev_pm_ops gpio_pm_ops = {
+	.suspend		= omap_gpio_suspend,
+	.resume			= omap_gpio_resume,
+};
+
 static struct platform_driver omap_gpio_driver = {
 	.probe		= omap_gpio_probe,
 	.driver		= {
 		.name	= "omap_gpio",
+		.pm	= &gpio_pm_ops,
 	},
 };
 
@@ -1275,16 +1333,3 @@ static int __init omap_gpio_drv_reg(void)
 	return platform_driver_register(&omap_gpio_driver);
 }
 postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-	if (cpu_is_omap16xx() || cpu_class_is_omap2())
-		register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
-	return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);
Signature · 1 line
1.7.0.4
#18 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 25 lines · Tarun Kanti DebBarma

Call runtime pm APIs pm_runtime_get_sync() and pm_runtime_put_sync() for enabling/disabling clocks appropriately. Remove syscore_ops and instead use dev_pm_ops now.

---
 drivers/gpio/gpio-omap.c |   89 ++++++++++++++++++++++++++++++++++-----------
 1 files changed, 67 insertions(+), 22 deletions(-)
drivers/gpio/gpio-omap.c +2 -0
index 6e7399c..f36931a 100644
@@ -79,6 +79,8 @@ struct gpio_bank {
 	struct omap_gpio_reg_offs *regs;
 };
 
+static void omap_gpio_mod_init(struct gpio_bank *bank);
+
 #define GPIO_INDEX(bank, gpio) (gpio % bank->width)
 #define GPIO_BIT(bank, gpio) (1 << GPIO_INDEX(bank, gpio))
 #define GPIO_MOD_CTRL_BIT	BIT(0)

drivers/gpio/gpio-omap.c static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) · line 486

Quoted 9 lines
drivers/gpio/gpio-omap.c +6 -0
@@ -476,6 +478,19 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 
 	spin_lock_irqsave(&bank->lock, flags);
 
+	/*
+	 * If this is the first gpio_request for the bank,
+	 * enable the bank module.
+	 */
+	if (!bank->mod_usage)
+		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {

All of the IS_ERR_VALUE() usage is wrong here. You're checking if the result of IS_ERR_VALUE() is < 0 which will never happen.

drivers/gpio/gpio-omap.c static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) · line 490

Quoted 4 lines
drivers/gpio/gpio-omap.c +4 -0
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_get_sync failed\n",
+					__func__, bank->id);
+			spin_unlock_irqrestore(&bank->lock, flags);

Rather than take the lock and have to unlock it here, just move the get_sync before the spinlock. There's no reason to hold the spinlock across the get_sync.

In fact, holding the spinlock across a get sync means that the ->runtime_resume callback does not have proper locking around register access, which is also probably wrong.

The locking in this driver is only around device register accesses, and should be kept minimal and to very small critical sections.

Quoted 13 lines
drivers/gpio/gpio-omap.c +6 -0
+			return -EINVAL;
+		}
+
 	/* Set trigger to none. You need to enable the desired trigger with
 	 * request_irq() or set_irq_type().
 	 */
@@ -530,6 +545,19 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 	}
 
 	_reset_gpio(bank, bank->chip.base + offset);
+
+	/*
+	 * If this is the last gpio to be freed in the bank,

drivers/gpio/gpio-omap.c static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) · line 560

Quoted 10 lines
drivers/gpio/gpio-omap.c +10 -0
+	 * disable the bank module.
+	 */
+	if (!bank->mod_usage) {
+		if (IS_ERR_VALUE(pm_runtime_put_sync(bank->dev) < 0)) {
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_put_sync failed\n",
+					__func__, bank->id);
+		}
+	}
+

same here, this should be after unlocking the spinlock, and register accesses inside the ->runtime_resume() callback need their own protection.

Quoted 12 lines
drivers/gpio/gpio-omap.c +1 -0
 	spin_unlock_irqrestore(&bank->lock, flags);
 }
 
@@ -556,6 +584,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
 	bank = irq_get_handler_data(irq);
 	isr_reg = bank->base + bank->regs->irqstatus;
+	pm_runtime_get_sync(bank->dev);
 
 	if (WARN_ON(!isr_reg))
 		goto exit;

drivers/gpio/gpio-omap.c static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc) · line 649

Quoted 4 lines
drivers/gpio/gpio-omap.c +1 -0
@@ -617,6 +646,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 exit:
 	if (!unmasked)
 		chained_irq_exit(chip, desc);
+	pm_runtime_put_sync_suspend(bank->dev);

Why use _put_sync_suspend()?

Why does this need to be synchronous? I think it should use the asynchronous pm_runtime_put().

Quoted 80 lines
drivers/gpio/gpio-omap.c +21 -9
 }
 
 static void gpio_irq_shutdown(struct irq_data *d)
@@ -1018,7 +1048,13 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	}
 
 	pm_runtime_enable(bank->dev);
-	pm_runtime_get_sync(bank->dev);
+	pm_runtime_irq_safe(bank->dev);
+	if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {
+		dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_get_sync "
+				"failed\n", __func__, bank->id);
+		iounmap(bank->base);
+		return -EINVAL;
+	}
 
 	if (bank->is_mpuio)
 		mpuio_init(bank);
@@ -1027,6 +1063,13 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 	omap_gpio_chip_init(bank);
 	omap_gpio_show_rev(bank);
 
+	if (IS_ERR_VALUE(pm_runtime_put_sync(bank->dev) < 0)) {
+		dev_err(bank->dev, "%s: GPIO bank %d pm_runtime_put_sync "
+				"failed\n", __func__, bank->id);
+		iounmap(bank->base);
+		return -EINVAL;
+	}
+
 	list_add_tail(&bank->node, &omap_gpio_list);
 
 	return ret;
@@ -1037,7 +1080,7 @@ err_exit:
 	return ret;
 }
 
-static int omap_gpio_suspend(void)
+static int omap_gpio_suspend(struct device *dev)
 {
 	struct gpio_bank *bank;
 
@@ -1055,12 +1098,13 @@ static int omap_gpio_suspend(void)
 		bank->saved_wakeup = __raw_readl(wake_status);
 		MOD_REG_BIT(bank->regs->wkup_en, bank->suspend_wakeup, 1);
 		spin_unlock_irqrestore(&bank->lock, flags);
+		pm_runtime_put_sync(dev);
 	}
 
 	return 0;
 }
 
-static void omap_gpio_resume(void)
+static int omap_gpio_resume(struct device *dev)
 {
 	struct gpio_bank *bank;
 
@@ -1069,18 +1113,16 @@ static void omap_gpio_resume(void)
 		unsigned long flags;
 
 		if (!bank->regs->wkup_en)
-			return;
+			return 0;
 
+		pm_runtime_get_sync(dev);
 		spin_lock_irqsave(&bank->lock, flags);
 		MOD_REG_BIT(bank->regs->wkup_en, bank->saved_wakeup, 1);
 		spin_unlock_irqrestore(&bank->lock, flags);
 	}
-}
 
-static struct syscore_ops omap_gpio_syscore_ops = {
-	.suspend	= omap_gpio_suspend,
-	.resume		= omap_gpio_resume,
-};
+	return 0;
+}
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
 

drivers/gpio/gpio-omap.c void omap2_gpio_prepare_for_idle(int off_mode) · line 1149

Quoted 4 lines
drivers/gpio/gpio-omap.c +1 -0
@@ -1104,6 +1146,11 @@ void omap2_gpio_prepare_for_idle(int off_mode)
 		if (!off_mode)
 			continue;
 
+		if (IS_ERR_VALUE(pm_runtime_put_sync_suspend(bank->dev) < 0))

_put_sync()

Quoted 20 lines
drivers/gpio/gpio-omap.c +9 -0
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_put_sync_suspend failed\n",
+					__func__, bank->id);
+
 		/* If going to OFF, remove triggering for all
 		 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
 		 * generated.  See OMAP2420 Errata item 1.101. */
@@ -1144,6 +1191,11 @@ void omap2_gpio_resume_after_idle(void)
 		if (!bank->loses_context)
 			continue;
 
+		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0))
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_get_sync failed\n",
+					__func__, bank->id);
+
 		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 			clk_enable(bank->dbck);
 

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 7 lines
drivers/gpio/gpio-omap.c +4 -0
@@ -1258,10 +1310,16 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 }
 #endif
 
+static const struct dev_pm_ops gpio_pm_ops = {
+	.suspend		= omap_gpio_suspend,
+	.resume			= omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). See <linux/pm.h>

Quoted 15 lines
drivers/gpio/gpio-omap.c +1 -3
 static struct platform_driver omap_gpio_driver = {
 	.probe		= omap_gpio_probe,
 	.driver		= {
 		.name	= "omap_gpio",
+		.pm	= &gpio_pm_ops,
 	},
 };
 
@@ -1275,16 +1333,3 @@ static int __init omap_gpio_drv_reg(void)
 	return platform_driver_register(&omap_gpio_driver);
 }
 postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{

drivers/gpio/gpio-omap.c static int __init omap_gpio_drv_reg(void) · line 1290

Quoted 10 lines
drivers/gpio/gpio-omap.c +0 -10
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
-	if (cpu_is_omap16xx() || cpu_class_is_omap2())
-		register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
-	return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);

Kevin

#19 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

[...]

Quoted 9 lines
Quoted 6 lines

+ ? ? /*
+ ? ? ?* If this is the first gpio_request for the bank,
+ ? ? ?* enable the bank module.
+ ? ? ?*/
+ ? ? if (!bank->mod_usage)
+ ? ? ? ? ? ? if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {

All of the IS_ERR_VALUE() usage is wrong here. ?You're checking if the result of IS_ERR_VALUE() is < 0 which will never happen.

No.
IS_ERR_VALUE is applied on the return value of pm_runtime_get_sync which is < 0.

Quoted 10 lines
Quoted 5 lines

+ ? ? ? ? ? ? ? ? ? ? dev_err(bank->dev, "%s: GPIO bank %d "
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "pm_runtime_get_sync failed\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __func__, bank->id);
+ ? ? ? ? ? ? ? ? ? ? spin_unlock_irqrestore(&bank->lock, flags);

Rather than take the lock and have to unlock it here, just move the get_sync before the spinlock. ?There's no reason to hold the spinlock across the get_sync.

Quoted 6 lines

In fact, holding the spinlock across a get sync means that the ->runtime_resume callback does not have proper locking around register access, which is also probably wrong.

The locking in this driver is only around device register accesses, and should be kept minimal and to very small critical sections.

You are right! I will move *_get_sync() outside spinlock.

Quoted 20 lines
Quoted 20 lines

+ ? ? ? ? ? ? ? ? ? ? return -EINVAL;
+ ? ? ? ? ? ? }
+
? ? ? /* Set trigger to none. You need to enable the desired trigger with ? ? ? ?* request_irq() or set_irq_type().
? ? ? ?*/

(quoted diff) +9 -0
@@ -530,6 +545,19 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 ? ? ? }
 
 ? ? ? _reset_gpio(bank, bank->chip.base + offset);
+
+ ? ? /*
+ ? ? ?* If this is the last gpio to be freed in the bank,
+ ? ? ?* disable the bank module.
+ ? ? ?*/
+ ? ? if (!bank->mod_usage) {
+ ? ? ? ? ? ? if (IS_ERR_VALUE(pm_runtime_put_sync(bank->dev) < 0)) {
+ ? ? ? ? ? ? ? ? ? ? dev_err(bank->dev, "%s: GPIO bank %d "
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "pm_runtime_put_sync failed\n",
Quoted 8 lines

Review static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) · line 560

Quoted 4 lines
(quoted diff) +4 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __func__, bank->id);
+ ? ? ? ? ? ? }
+ ? ? }
+

same here, this should be after unlocking the spinlock, and register accesses inside the ->runtime_resume() callback need their own protection.

Ok.

Quoted 20 lines
Quoted 13 lines
(quoted diff) +1 -0
 ? ? ? spin_unlock_irqrestore(&bank->lock, flags);
 ?}
 
@@ -556,6 +584,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
 
 ? ? ? bank = irq_get_handler_data(irq);
 ? ? ? isr_reg = bank->base + bank->regs->irqstatus;
+ ? ? pm_runtime_get_sync(bank->dev);
 
 ? ? ? if (WARN_ON(!isr_reg))
 ? ? ? ? ? ? ? goto exit;
@@ -617,6 +646,7 @@ static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
Quoted 4 lines

?exit:
? ? ? if (!unmasked)
? ? ? ? ? ? ? chained_irq_exit(chip, desc);
+ ? ? pm_runtime_put_sync_suspend(bank->dev);

Why use _put_sync_suspend()?

Quoted 2 lines

Why does this need to be synchronous? ?I think it should use the asynchronous pm_runtime_put().

I will change it to pm_runtime_put().

Quoted 1 line

[...]

Quoted 11 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 9 lines
(quoted diff) +0 -0
@@ -1258,10 +1310,16 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ?}

?#endif

drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

Ok.

Quoted 29 lines
Quoted 16 lines

?static struct platform_driver omap_gpio_driver = { ? ? ? .probe ? ? ? ? ?= omap_gpio_probe,
? ? ? .driver ? ? ? ? = {
? ? ? ? ? ? ? .name ? = "omap_gpio",
+ ? ? ? ? ? ? .pm ? ? = &gpio_pm_ops,
? ? ? },
?};

drivers/gpio/gpio-omap.c +0 -3
@@ -1275,16 +1333,3 @@ static int __init omap_gpio_drv_reg(void)
 ? ? ? return platform_driver_register(&omap_gpio_driver);
 ?}
 ?postcore_initcall(omap_gpio_drv_reg);
-
-static int __init omap_gpio_sysinit(void)
-{

drivers/gpio/gpio-omap.c static int __init omap_gpio_drv_reg(void) · line 1290

Quoted 10 lines
drivers/gpio/gpio-omap.c +0 -10
-
-#if defined(CONFIG_ARCH_OMAP16XX) || defined(CONFIG_ARCH_OMAP2PLUS)
- ? ? if (cpu_is_omap16xx() || cpu_class_is_omap2())
- ? ? ? ? ? ? register_syscore_ops(&omap_gpio_syscore_ops);
-#endif
-
- ? ? return 0;
-}
-
-arch_initcall(omap_gpio_sysinit);

Kevin

#20 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 8 lines · Tarun Kanti

[...]

Quoted 7 lines
Quoted 6 lines

+ ? ? /*
+ ? ? ?* If this is the first gpio_request for the bank,
+ ? ? ?* enable the bank module.
+ ? ? ?*/
+ ? ? if (!bank->mod_usage)
+ ? ? ? ? ? ? if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {

Quoted 5 lines
Quoted 2 lines

All of the IS_ERR_VALUE() usage is wrong here. ?You're checking if the result of IS_ERR_VALUE() is < 0 which will never happen.

No.
IS_ERR_VALUE is applied on the return value of pm_runtime_get_sync which is < 0.

...and is still not correct.

The result of the '< 0' check will be zero or one, so IS_ERR_VALUE() will never be true.

Kevin

#21 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 12 lines · Kevin Hilman
Quoted 10 lines · Tarun Kanti

[...]

Quoted 9 lines
Quoted 6 lines

+ ? ? /*
+ ? ? ?* If this is the first gpio_request for the bank,
+ ? ? ?* enable the bank module.
+ ? ? ?*/
+ ? ? if (!bank->mod_usage)
+ ? ? ? ? ? ? if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {

All of the IS_ERR_VALUE() usage is wrong here. ?You're checking if the result of IS_ERR_VALUE() is < 0 which will never happen.

Quoted 8 lines
Quoted 3 lines

No.
IS_ERR_VALUE is applied on the return value of pm_runtime_get_sync which is < ?0.

...and is still not correct.

The result of the '< 0' check will be zero or one, so IS_ERR_VALUE() will never be true.

Ok.

Quoted 3 lines

Kevin

#22 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

In reply to Kevin Hilman

[...]

Quoted 7 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 5 lines
drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

We can use following macro to initialize .suspend and .resume callbacks. But how do we initialize .runtime_suspend and .runtime_resume callbacks?

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \

const struct dev_pm_ops name = { \
        SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

Do we have something similar to following where we can assign separate pair of callbacks?
The following macro on the other hand assigns the same set of callbacks to both and this not what I want!!!

#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \

const struct dev_pm_ops name = { \
        SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
        SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
}

--
Tarun

Quoted 8 lines
Quoted 8 lines

?static struct platform_driver omap_gpio_driver = { ? ? ? .probe ? ? ? ? ?= omap_gpio_probe,
? ? ? .driver ? ? ? ? = {
? ? ? ? ? ? ? .name ? = "omap_gpio",
+ ? ? ? ? ? ? .pm ? ? = &gpio_pm_ops,
? ? ? },
?};

[...]

#23 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 21 lines · Tarun Kanti

[...]

Quoted 7 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 5 lines
drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

We can use following macro to initialize .suspend and .resume callbacks. But how do we initialize .runtime_suspend and .runtime_resume callbacks?

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops name = { \
? ? ? ?SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

Do we have something similar to following where we can assign separate pair of callbacks?
The following macro on the other hand assigns the same set of callbacks to both and this not what I want!!!

Quoted 5 lines

#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \
const struct dev_pm_ops name = { \
? ? ? ?SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
? ? ? ?SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
}

Ok, I saw an example... Thanks!!

Quoted 13 lines

--
Tarun

Quoted 8 lines
Quoted 8 lines

?static struct platform_driver omap_gpio_driver = { ? ? ? .probe ? ? ? ? ?= omap_gpio_probe,
? ? ? .driver ? ? ? ? = {
? ? ? ? ? ? ? .name ? = "omap_gpio",
+ ? ? ? ? ? ? .pm ? ? = &gpio_pm_ops,
? ? ? },
?};

[...]

#24 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

In reply to DebBarma, Tarun Kanti
Quoted 11 lines · Tarun Kanti

[...]

Quoted 7 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 5 lines
drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

We can use following macro to initialize .suspend and .resume callbacks. But how do we initialize .runtime_suspend and .runtime_resume callbacks?

Quoted 7 lines

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \

const struct dev_pm_ops name = { \
        SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

Do we have something similar to following where we can assign separate pair of callbacks?

SET_RUNTIME_PM_OPS()

Kevin

#25 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 18 lines · Kevin Hilman
Quoted 16 lines · Tarun Kanti

[...]

Quoted 7 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 5 lines
drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

We can use following macro to initialize .suspend and .resume callbacks. But how do we initialize .runtime_suspend and .runtime_resume callbacks?

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops name = { \
? ? ? ? SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

Quoted 4 lines
Quoted 2 lines

Do we have something similar to following where we can assign separate pair of callbacks?

SET_RUNTIME_PM_OPS()

Yes, I have done this way:

static const struct dev_pm_ops gpio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL)
};

--
Tarun

Quoted 3 lines

Kevin

#26 lore raw

PATCH v6 17/25 gpio/omap: use pm-runtime framework

Quoted 22 lines · Tarun Kanti
Quoted 21 lines · Kevin Hilman
Quoted 18 lines · Tarun Kanti

[...]

Quoted 7 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1316

Quoted 5 lines
drivers/gpio/gpio-omap.c +4 -0
+static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend,
+ ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume,
+};

Please use SET_SYSTEM_SLEEP_PM_OPS(). ?See <linux/pm.h>

We can use following macro to initialize .suspend and .resume callbacks. But how do we initialize .runtime_suspend and .runtime_resume callbacks?

#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \
const struct dev_pm_ops name = { \
? ? ? ? SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \
}

Do we have something similar to following where we can assign separate pair of callbacks?

Quoted 7 lines
Quoted 1 line

SET_RUNTIME_PM_OPS()

Yes, I have done this way:

static const struct dev_pm_ops gpio_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap_gpio_suspend, omap_gpio_resume) SET_RUNTIME_PM_OPS(omap_gpio_runtime_suspend, omap_gpio_runtime_resume,
NULL)

Perfect.

Kevin

#27 lore raw

PATCH v6 18/25 gpio/omap: optimize suspend and resume functions

In reply to Tarun Kanti DebBarma

There is no need to operate on all the banks every time the function is called. Just operate on the current bank passed by the framework.

---
 drivers/gpio/gpio-omap.c |   53 +++++++++++++++++++++------------------------
 1 files changed, 25 insertions(+), 28 deletions(-)
drivers/gpio/gpio-omap.c +25 -28
index f36931a..a267a30 100644
@@ -1047,6 +1047,8 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
 		goto err_free;
 	}
 
+	platform_set_drvdata(pdev, bank);
+
 	pm_runtime_enable(bank->dev);
 	pm_runtime_irq_safe(bank->dev);
 	if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0)) {
@@ -1082,44 +1084,39 @@ err_exit:
 
 static int omap_gpio_suspend(struct device *dev)
 {
-	struct gpio_bank *bank;
-
-	list_for_each_entry(bank, &omap_gpio_list, node) {
-		void __iomem *base = bank->base;
-		void __iomem *wake_status;
-		unsigned long flags;
-
-		if (!bank->regs->wkup_en)
-			return 0;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	void __iomem *base = bank->base;
+	void __iomem *wake_status;
+	unsigned long flags;
 
-		wake_status = bank->base + bank->regs->wkup_en;
+	if (!bank->regs->wkup_en || !bank->suspend_wakeup)
+		return 0;
 
-		spin_lock_irqsave(&bank->lock, flags);
-		bank->saved_wakeup = __raw_readl(wake_status);
-		MOD_REG_BIT(bank->regs->wkup_en, bank->suspend_wakeup, 1);
-		spin_unlock_irqrestore(&bank->lock, flags);
-		pm_runtime_put_sync(dev);
-	}
+	wake_status = bank->base + bank->regs->wkup_en;
 
+	spin_lock_irqsave(&bank->lock, flags);
+	bank->saved_wakeup = __raw_readl(wake_status);
+	MOD_REG_BIT(bank->regs->wkup_en, bank->suspend_wakeup, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	pm_runtime_put_sync(dev);
 	return 0;
 }
 
 static int omap_gpio_resume(struct device *dev)
 {
-	struct gpio_bank *bank;
-
-	list_for_each_entry(bank, &omap_gpio_list, node) {
-		void __iomem *base = bank->base;
-		unsigned long flags;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	void __iomem *base = bank->base;
+	unsigned long flags;
 
-		if (!bank->regs->wkup_en)
-			return 0;
+	if (!bank->regs->wkup_en || !bank->saved_wakeup)
+		return 0;
 
-		pm_runtime_get_sync(dev);
-		spin_lock_irqsave(&bank->lock, flags);
-		MOD_REG_BIT(bank->regs->wkup_en, bank->saved_wakeup, 1);
-		spin_unlock_irqrestore(&bank->lock, flags);
-	}
+	pm_runtime_get_sync(dev);
+	spin_lock_irqsave(&bank->lock, flags);
+	MOD_REG_BIT(bank->regs->wkup_en, bank->saved_wakeup, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
 
 	return 0;
 }
Signature · 1 line
1.7.0.4
#28 lore raw

PATCH v6 19/25 gpio/omap: cleanup prepare_for_idle and resume_after_idle

In reply to Tarun Kanti DebBarma

Cleanup omap2_gpio_prepare_for_idle() and omap2_gpio_resume_after_idle() by moving most of the stuff to *_runtime_suspend() and *_runtime_resume().

---
 drivers/gpio/gpio-omap.c |  234 ++++++++++++++++++++++++---------------------
 1 files changed, 125 insertions(+), 109 deletions(-)
drivers/gpio/gpio-omap.c +125 -109
index a267a30..9d68b15 100644
@@ -1126,142 +1126,153 @@ static int omap_gpio_resume(struct device *dev)
 static void omap_gpio_save_context(struct gpio_bank *bank);
 static void omap_gpio_restore_context(struct gpio_bank *bank);
 
-void omap2_gpio_prepare_for_idle(int off_mode)
+static int omap_gpio_runtime_suspend(struct device *dev)
 {
-	struct gpio_bank *bank;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	u32 l1 = 0, l2 = 0;
+	int j;
 
-	list_for_each_entry(bank, &omap_gpio_list, node) {
-		u32 l1 = 0, l2 = 0;
-		int j;
+	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
+		clk_disable(bank->dbck);
 
-		if (!bank->loses_context)
-			continue;
+	/*
+	 * If going to OFF, remove triggering for all
+	 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
+	 * generated.  See OMAP2420 Errata item 1.101.
+	 */
+	if (!(bank->enabled_non_wakeup_gpios))
+		goto save_gpio_context;
 
-		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-			clk_disable(bank->dbck);
+	bank->saved_datain = __raw_readl(bank->base +
+						bank->regs->datain);
+	l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
+	l2 = __raw_readl(bank->base + bank->regs->risingdetect);
 
-		if (!off_mode)
-			continue;
+	bank->saved_fallingdetect = l1;
+	bank->saved_risingdetect = l2;
+	l1 &= ~bank->enabled_non_wakeup_gpios;
+	l2 &= ~bank->enabled_non_wakeup_gpios;
 
-		if (IS_ERR_VALUE(pm_runtime_put_sync_suspend(bank->dev) < 0))
-			dev_err(bank->dev, "%s: GPIO bank %d "
-					"pm_runtime_put_sync_suspend failed\n",
-					__func__, bank->id);
+	__raw_writel(l1, bank->base + bank->regs->fallingdetect);
+	__raw_writel(l2, bank->base + bank->regs->risingdetect);
+
+save_gpio_context:
+	if (bank->get_context_loss_count)
+		bank->context_loss_count =
+				bank->get_context_loss_count(bank->dev);
+	omap_gpio_save_context(bank);
 
-		/* If going to OFF, remove triggering for all
-		 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
-		 * generated.  See OMAP2420 Errata item 1.101. */
-		if (!(bank->enabled_non_wakeup_gpios))
-			goto save_gpio_context;
+	return 0;
+}
+
+static int omap_gpio_runtime_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct gpio_bank *bank = platform_get_drvdata(pdev);
+	u32 context_lost_cnt_after;
+	u32 l = 0, gen, gen0, gen1;
+	int j;
+
+	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
+		clk_enable(bank->dbck);
 
-		bank->saved_datain = __raw_readl(bank->base +
-							bank->regs->datain);
-		l1 = __raw_readl(bank->base + bank->regs->fallingdetect);
-		l2 = __raw_readl(bank->base + bank->regs->risingdetect);
+	if (bank->get_context_loss_count) {
+		context_lost_cnt_after =
+			bank->get_context_loss_count(bank->dev);
+		if (context_lost_cnt_after != bank->context_loss_count ||
+						!context_lost_cnt_after)
+			omap_gpio_restore_context(bank);
+		else
+			return 0;
+	}
 
-		bank->saved_fallingdetect = l1;
-		bank->saved_risingdetect = l2;
-		l1 &= ~bank->enabled_non_wakeup_gpios;
-		l2 &= ~bank->enabled_non_wakeup_gpios;
+	if (!(bank->enabled_non_wakeup_gpios))
+		return 0;
 
-		__raw_writel(l1, bank->base + bank->regs->fallingdetect);
-		__raw_writel(l2, bank->base + bank->regs->risingdetect);
+	__raw_writel(bank->saved_fallingdetect,
+			bank->base + bank->regs->fallingdetect);
+	__raw_writel(bank->saved_risingdetect,
+			bank->base + bank->regs->risingdetect);
+	l = __raw_readl(bank->base + bank->regs->datain);
 
-save_gpio_context:
-		if (bank->get_context_loss_count)
-			bank->context_loss_count =
-				bank->get_context_loss_count(bank->dev);
+	/*
+	 * Check if any of the non-wakeup interrupt GPIOs have changed
+	 * state.  If so, generate an IRQ by software.  This is
+	 * horribly racy, but it's the best we can do to work around
+	 * this silicon bug.
+	 */
+	l ^= bank->saved_datain;
+	l &= bank->enabled_non_wakeup_gpios;
 
-		omap_gpio_save_context(bank);
+	/*
+	 * No need to generate IRQs for the rising edge for gpio IRQs
+	 * configured with falling edge only; and vice versa.
+	 */
+	gen0 = l & bank->saved_fallingdetect;
+	gen0 &= bank->saved_datain;
+	gen1 = l & bank->saved_risingdetect;
+	gen1 &= ~(bank->saved_datain);
+
+	/* FIXME: Consider GPIO IRQs with level detections properly! */
+	gen = l & (~(bank->saved_fallingdetect) & ~(bank->saved_risingdetect));
+	/* Consider all GPIO IRQs needed to be updated */
+	gen |= gen0 | gen1;
+
+	if (gen) {
+		u32 old0, old1;
+
+		old0 = __raw_readl(bank->base + bank->regs->leveldetect0);
+		old1 = __raw_readl(bank->base + bank->regs->leveldetect1);
+
+		__raw_writel(old0, bank->base + bank->regs->leveldetect0);
+		__raw_writel(old1, bank->base + bank->regs->leveldetect1);
+		if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
+			old0 |= gen;
+			old1 |= gen;
+		}
+
+		if (cpu_is_omap44xx()) {
+			old0 |= l;
+			old1 |= l;
+		}
+		__raw_writel(old0, bank->base + bank->regs->leveldetect0);
+		__raw_writel(old1, bank->base + bank->regs->leveldetect1);
 	}
+
+	return 0;
 }
 
-void omap2_gpio_resume_after_idle(void)
+void omap2_gpio_prepare_for_idle(int off_mode)
 {
 	struct gpio_bank *bank;
 
-	list_for_each_entry(bank, &omap_gpio_list, node) {
-		u32 context_lost_cnt_after;
-		u32 l = 0, gen, gen0, gen1;
-		int j;
+	if (!off_mode)
+		return;
 
-		if (!bank->loses_context)
+	list_for_each_entry(bank, &omap_gpio_list, node) {
+		if (!bank->mod_usage || !bank->loses_context)
 			continue;
 
-		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0))
+		if (IS_ERR_VALUE(pm_runtime_put_sync_suspend(bank->dev) < 0))
 			dev_err(bank->dev, "%s: GPIO bank %d "
-					"pm_runtime_get_sync failed\n",
+					"pm_runtime_put_sync_suspend failed\n",
 					__func__, bank->id);
+	}
+}
 
-		for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-			clk_enable(bank->dbck);
-
-		if (bank->get_context_loss_count) {
-			context_lost_cnt_after =
-				bank->get_context_loss_count(bank->dev);
-			if (context_lost_cnt_after != bank->context_loss_count
-				|| !context_lost_cnt_after)
-				omap_gpio_restore_context(bank);
-		}
+void omap2_gpio_resume_after_idle(void)
+{
+	struct gpio_bank *bank;
 
-		if (!(bank->enabled_non_wakeup_gpios))
+	list_for_each_entry(bank, &omap_gpio_list, node) {
+		if (!bank->mod_usage || !bank->loses_context)
 			continue;
 
-		__raw_writel(bank->saved_fallingdetect,
-				bank->base + bank->regs->fallingdetect);
-		__raw_writel(bank->saved_risingdetect,
-				bank->base + bank->regs->risingdetect);
-		l = __raw_readl(bank->base + bank->regs->datain);
-
-		/* Check if any of the non-wakeup interrupt GPIOs have changed
-		 * state.  If so, generate an IRQ by software.  This is
-		 * horribly racy, but it's the best we can do to work around
-		 * this silicon bug. */
-		l ^= bank->saved_datain;
-		l &= bank->enabled_non_wakeup_gpios;
-
-		/*
-		 * No need to generate IRQs for the rising edge for gpio IRQs
-		 * configured with falling edge only; and vice versa.
-		 */
-		gen0 = l & bank->saved_fallingdetect;
-		gen0 &= bank->saved_datain;
-
-		gen1 = l & bank->saved_risingdetect;
-		gen1 &= ~(bank->saved_datain);
-
-		/* FIXME: Consider GPIO IRQs with level detections properly! */
-		gen = l & (~(bank->saved_fallingdetect) &
-				~(bank->saved_risingdetect));
-		/* Consider all GPIO IRQs needed to be updated */
-		gen |= gen0 | gen1;
-
-		if (gen) {
-			u32 old0, old1;
-
-			old0 = __raw_readl(bank->base +
-						bank->regs->leveldetect0);
-			old1 = __raw_readl(bank->base +
-						bank->regs->leveldetect1);
-
-			__raw_writel(old0, bank->base +
-						bank->regs->leveldetect0);
-			__raw_writel(old1, bank->base +
-						bank->regs->leveldetect1);
-			if (cpu_is_omap24xx() || cpu_is_omap34xx()) {
-				old0 |= gen;
-				old1 |= gen;
-			}
-
-			if (cpu_is_omap44xx()) {
-				old0 |= l;
-				old1 |= l;
-			}
-			__raw_writel(old0, bank->base +
-						bank->regs->leveldetect0);
-			__raw_writel(old1, bank->base +
-						bank->regs->leveldetect1);
-		}
+		if (IS_ERR_VALUE(pm_runtime_get_sync(bank->dev) < 0))
+			dev_err(bank->dev, "%s: GPIO bank %d "
+					"pm_runtime_get_sync failed\n",
+					__func__, bank->id);
 	}
 }
 
@@ -1305,9 +1316,14 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
 }
+#else
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL
 #endif
 
 static const struct dev_pm_ops gpio_pm_ops = {
+	.runtime_suspend	= omap_gpio_runtime_suspend,
+	.runtime_resume		= omap_gpio_runtime_resume,
 	.suspend		= omap_gpio_suspend,
 	.resume			= omap_gpio_resume,
 };
Signature · 1 line
1.7.0.4
#29 lore raw

PATCH v6 19/25 gpio/omap: cleanup prepare_for_idle and resume_after_idle

Quoted 2 lines · Tarun Kanti DebBarma

Cleanup omap2_gpio_prepare_for_idle() and omap2_gpio_resume_after_idle() by moving most of the stuff to *_runtime_suspend() and *_runtime_resume().

Why?

(I know the answer, but it should be in the changelog.)

Quoted 3 lines

Also, as pointed out in an earlier patch, now that this is moved out of the idle path, where interrupts were known to be disabled, the register accesses in the runtime PM callbacks need to be protected by the spinlock just like they are in other parts of the driver.

[...]

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1326

Quoted 12 lines
drivers/gpio/gpio-omap.c +5 -0
@@ -1305,9 +1316,14 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
 }
+#else
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL
 #endif
 
 static const struct dev_pm_ops gpio_pm_ops = {
+	.runtime_suspend	= omap_gpio_runtime_suspend,
+	.runtime_resume		= omap_gpio_runtime_resume,

Please use SET_RUNTIME_PM_OPS() (see <linux/pm.h.)

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1329

Quoted 3 lines
drivers/gpio/gpio-omap.c +0 -0
 	.suspend		= omap_gpio_suspend,
 	.resume			= omap_gpio_resume,
 };

Kevin

#30 lore raw

PATCH v6 19/25 gpio/omap: cleanup prepare_for_idle and resume_after_idle

Quoted 8 lines · Kevin Hilman
Quoted 2 lines · Tarun Kanti DebBarma

Cleanup ?omap2_gpio_prepare_for_idle() and omap2_gpio_resume_after_idle() by moving most of the stuff to *_runtime_suspend() and *_runtime_resume().

Why?

(I know the answer, but it should be in the changelog.)

Ok.

Quoted 9 lines
Quoted 4 lines

Also, as pointed out in an earlier patch, now that this is moved out of the idle path, where interrupts were known to be disabled, the register accesses in the runtime PM callbacks need to be protected by the spinlock just like they are in other parts of the driver.

Ok.

Quoted 12 lines

[...]

Quoted 9 lines
drivers/gpio/gpio-omap.c +3 -0
@@ -1305,9 +1316,14 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->fallingdetect);
 ? ? ? __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
 ?}
+#else
+#define omap_gpio_runtime_suspend NULL
+#define omap_gpio_runtime_resume NULL

?#endif

Quoted 5 lines
Quoted 3 lines

?static const struct dev_pm_ops gpio_pm_ops = {
+ ? ? .runtime_suspend ? ? ? ?= omap_gpio_runtime_suspend,
+ ? ? .runtime_resume ? ? ? ? = omap_gpio_runtime_resume,

Please use SET_RUNTIME_PM_OPS() (see <linux/pm.h.)

Sure.

Quoted 7 lines
Quoted 4 lines

? ? ? .suspend ? ? ? ? ? ? ? ?= omap_gpio_suspend, ? ? ? .resume ? ? ? ? ? ? ? ? = omap_gpio_resume, ?};

Kevin

#31 lore raw

PATCH v6 20/25 gpio/omap: skip operations in runtime callbacks

In reply to Tarun Kanti DebBarma

Most operations within runtime callbacks should be skipped when *_runtime_get_sync() and *_runtime_put_sync() are called in probe(), *_gpio_request() and *_gpio_free(). We just need clock enable/disable.

---
 drivers/gpio/gpio-omap.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
drivers/gpio/gpio-omap.c +6 -0
index 9d68b15..67c5a96 100644
@@ -1136,6 +1136,9 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 		clk_disable(bank->dbck);
 
+	if (!bank->mod_usage)
+		return 0;
+
 	/*
 	 * If going to OFF, remove triggering for all
 	 * non-wakeup GPIOs.  Otherwise spurious IRQs will be
@@ -1177,6 +1180,9 @@ static int omap_gpio_runtime_resume(struct device *dev)
 	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
 		clk_enable(bank->dbck);
 
+	if (!bank->mod_usage)
+		return 0;
+
 	if (bank->get_context_loss_count) {
 		context_lost_cnt_after =
 			bank->get_context_loss_count(bank->dev);
Signature · 1 line
1.7.0.4
#32 lore raw

PATCH v6 20/25 gpio/omap: skip operations in runtime callbacks

Quoted 3 lines · Tarun Kanti DebBarma

Most operations within runtime callbacks should be skipped when *_runtime_get_sync() and *_runtime_put_sync() are called in probe(), *_gpio_request() and *_gpio_free().

Why?

(again, I know the answer, but should be described in the changelog for folks not familiar with this driver, or when we come back to this in 3 months and have forgotten why.

Quoted 4 lines

We just need clock enable/disable.

Kevin

#33 lore raw

PATCH v6 20/25 gpio/omap: skip operations in runtime callbacks

Quoted 11 lines · Kevin Hilman
Quoted 3 lines · Tarun Kanti DebBarma

Most operations within runtime callbacks should be skipped when *_runtime_get_sync() and *_runtime_put_sync() are called in probe(), *_gpio_request() and *_gpio_free().

Why?

(again, I know the answer, but should be described in the changelog for folks not familiar with this driver, or when we come back to this in 3 months and have forgotten why.

Ok.

Quoted 8 lines
Quoted 5 lines

We just need clock enable/disable.

Kevin

#34 lore raw

PATCH v6 21/25 gpio/omap: remove omap_gpio_save_context overhead

In reply to Tarun Kanti DebBarma

Context is now saved dynamically in respective functions whenever and whichever registers are modified. This avoid overhead of saving all registers context in the runtime callback.

---
 drivers/gpio/gpio-omap.c |   62 ++++++++++++++++++++++++++-------------------
 1 files changed, 36 insertions(+), 26 deletions(-)
drivers/gpio/gpio-omap.c +36 -26
index 67c5a96..dc382f6 100644
@@ -97,6 +97,7 @@ static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
 	else
 		l &= ~(1 << gpio);
 	__raw_writel(l, reg);
+	bank->context.oe = l;
 }
 
 
@@ -127,6 +128,7 @@ static void _set_gpio_dataout_mask(struct gpio_bank *bank, int gpio, int enable)
 	else
 		l &= ~gpio_bit;
 	__raw_writel(l, reg);
+	bank->context.dataout = l;
 }
 
 static int _get_gpio_datain(struct gpio_bank *bank, int gpio)
@@ -212,9 +214,20 @@ static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
 	MOD_REG_BIT(bank->regs->fallingdetect, gpio_bit,
 		  trigger & IRQ_TYPE_EDGE_FALLING);
 
-	if (likely(!(bank->non_wakeup_gpios & gpio_bit)))
+	bank->context.leveldetect0 =
+			__raw_readl(bank->base + bank->regs->leveldetect0);
+	bank->context.leveldetect1 =
+			__raw_readl(bank->base + bank->regs->leveldetect1);
+	bank->context.risingdetect =
+			__raw_readl(bank->base + bank->regs->risingdetect);
+	bank->context.fallingdetect =
+			__raw_readl(bank->base + bank->regs->fallingdetect);
+	if (likely(!(bank->non_wakeup_gpios & gpio_bit))) {
 		MOD_REG_BIT(bank->regs->wkup_en, gpio_bit,
 			trigger != 0);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
+	}
 
 	/* This part needs to be executed always for OMAP{34xx, 44xx} */
 	if (cpu_is_omap34xx() || cpu_is_omap44xx() ||
@@ -301,6 +314,8 @@ static int _set_gpio_triggering(struct gpio_bank *bank, int gpio, int trigger)
 
 		/* Enable wake-up during idle for dynamic tick */
 		MOD_REG_BIT(bank->regs->wkup_en, 1 << gpio, trigger);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
 		__raw_writel(l, reg);
 	}
 	return 0;
@@ -393,6 +408,7 @@ static void _enable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 	}
 
 	__raw_writel(l, reg);
+	bank->context.irqenable1 = l;
 }
 
 static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
@@ -413,6 +429,7 @@ static void _disable_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
 	}
 
 	__raw_writel(l, reg);
+	bank->context.irqenable1 = l;
 }
 
 static inline void _set_gpio_irqenable(struct gpio_bank *bank, int gpio, int enable)
@@ -511,6 +528,7 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 		/* Module is enabled, clocks are not gated */
 		ctrl &= ~GPIO_MOD_CTRL_BIT;
 		__raw_writel(ctrl, reg);
+		bank->context.ctrl = ctrl;
 	}
 
 	bank->mod_usage |= 1 << offset;
@@ -528,9 +546,12 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 
 	spin_lock_irqsave(&bank->lock, flags);
 
-	if (bank->regs->wkup_en)
+	if (bank->regs->wkup_en) {
 		/* Disable wake-up during idle for dynamic tick */
 		MOD_REG_BIT(bank->regs->wkup_en, 1 << offset, 0);
+		bank->context.wake_en =
+			__raw_readl(bank->base + bank->regs->wkup_en);
+	}
 
 	bank->mod_usage &= ~(1 << offset);
 
@@ -542,6 +563,7 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 		/* Module is disabled, clocks are gated */
 		ctrl |= GPIO_MOD_CTRL_BIT;
 		__raw_writel(ctrl, reg);
+		bank->context.ctrl = ctrl;
 	}
 
 	_reset_gpio(bank, bank->chip.base + offset);
@@ -908,6 +930,8 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
 					bank->regs->irqenable_inv == false);
 	MOD_REG_BIT(bank->regs->irqenable, l, bank->regs->debounce_en != 0);
 	MOD_REG_BIT(bank->regs->irqenable, l, bank->regs->ctrl != 0);
+	bank->context.irqenable1 =
+			__raw_readl(bank->base + bank->regs->irqenable);
 }
 
 static __init void
@@ -1098,6 +1122,7 @@ static int omap_gpio_suspend(struct device *dev)
 	spin_lock_irqsave(&bank->lock, flags);
 	bank->saved_wakeup = __raw_readl(wake_status);
 	MOD_REG_BIT(bank->regs->wkup_en, bank->suspend_wakeup, 1);
+	bank->context.wake_en = __raw_readl(bank->base + bank->regs->wkup_en);
 	spin_unlock_irqrestore(&bank->lock, flags);
 	pm_runtime_put_sync(dev);
 	return 0;
@@ -1116,6 +1141,7 @@ static int omap_gpio_resume(struct device *dev)
 	pm_runtime_get_sync(dev);
 	spin_lock_irqsave(&bank->lock, flags);
 	MOD_REG_BIT(bank->regs->wkup_en, bank->saved_wakeup, 1);
+	bank->context.wake_en = __raw_readl(bank->base + bank->regs->wkup_en);
 	spin_unlock_irqrestore(&bank->lock, flags);
 
 	return 0;
@@ -1123,7 +1149,6 @@ static int omap_gpio_resume(struct device *dev)
 
 #ifdef CONFIG_ARCH_OMAP2PLUS
 
-static void omap_gpio_save_context(struct gpio_bank *bank);
 static void omap_gpio_restore_context(struct gpio_bank *bank);
 
 static int omap_gpio_runtime_suspend(struct device *dev)
@@ -1145,7 +1170,7 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 	 * generated.  See OMAP2420 Errata item 1.101.
 	 */
 	if (!(bank->enabled_non_wakeup_gpios))
-		goto save_gpio_context;
+		goto update_gpio_context_count;
 
 	bank->saved_datain = __raw_readl(bank->base +
 						bank->regs->datain);
@@ -1159,12 +1184,13 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 
 	__raw_writel(l1, bank->base + bank->regs->fallingdetect);
 	__raw_writel(l2, bank->base + bank->regs->risingdetect);
+	bank->context.fallingdetect = l1;
+	bank->context.risingdetect = l2;
 
-save_gpio_context:
+update_gpio_context_count:
 	if (bank->get_context_loss_count)
 		bank->context_loss_count =
 				bank->get_context_loss_count(bank->dev);
-	omap_gpio_save_context(bank);
 
 	return 0;
 }
@@ -1200,6 +1226,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
 			bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->saved_risingdetect,
 			bank->base + bank->regs->risingdetect);
+	bank->context.fallingdetect = bank->saved_fallingdetect;
+	bank->context.risingdetect = bank->saved_risingdetect;
 	l = __raw_readl(bank->base + bank->regs->datain);
 
 	/*
@@ -1244,6 +1272,8 @@ static int omap_gpio_runtime_resume(struct device *dev)
 		}
 		__raw_writel(old0, bank->base + bank->regs->leveldetect0);
 		__raw_writel(old1, bank->base + bank->regs->leveldetect1);
+		bank->context.leveldetect0 = old0;
+		bank->context.leveldetect1 = old1;
 	}
 
 	return 0;
@@ -1282,26 +1312,6 @@ void omap2_gpio_resume_after_idle(void)
 	}
 }
 
-static void omap_gpio_save_context(struct gpio_bank *bank)
-{
-	bank->context.irqenable1 =
-			__raw_readl(bank->base + bank->regs->irqenable);
-	bank->context.irqenable2 =
-			__raw_readl(bank->base + bank->regs->irqenable2);
-	bank->context.wake_en =
-			__raw_readl(bank->base + bank->regs->wkup_en);
-	bank->context.ctrl = __raw_readl(bank->base + bank->regs->ctrl);
-	bank->context.oe = __raw_readl(bank->base + bank->regs->direction);
-	bank->context.leveldetect0 =
-			__raw_readl(bank->base + bank->regs->leveldetect0);
-	bank->context.leveldetect1 =
-			__raw_readl(bank->base + bank->regs->leveldetect1);
-	bank->context.risingdetect =
-			__raw_readl(bank->base + bank->regs->risingdetect);
-	bank->context.fallingdetect =
-	bank->context.dataout = __raw_readl(bank->base + bank->regs->dataout);
-}
-
 static void omap_gpio_restore_context(struct gpio_bank *bank)
 {
 	__raw_writel(bank->context.irqenable1,
Signature · 1 line
1.7.0.4
#35 lore raw

PATCH v6 21/25 gpio/omap: remove omap_gpio_save_context overhead

Quoted 3 lines · Tarun Kanti DebBarma

Context is now saved dynamically in respective functions whenever and whichever registers are modified. This avoid overhead of saving all registers context in the runtime callback.

Nice!

s/runtime callback/runtime suspend callback/

Quoted 2 lines

Kevin

#36 lore raw

PATCH v6 22/25 gpio/omap: save and restore debounce registers

In reply to Tarun Kanti DebBarma

From: Nishant Menon <[email protected]>

GPIO debounce registers need to be saved and restored for proper functioning of driver. To save the registers, we cannot cut the clock before the save, hence move the clk disable after the save.

---
 drivers/gpio/gpio-omap.c |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)
drivers/gpio/gpio-omap.c +19 -3
index dc382f6..67e08e9 100644
@@ -41,6 +41,8 @@ struct gpio_regs {
 	u32 risingdetect;
 	u32 fallingdetect;
 	u32 dataout;
+	u32 debounce;
+	u32 debounce_en;
 };
 
 struct gpio_bank {
@@ -1158,9 +1160,6 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 	u32 l1 = 0, l2 = 0;
 	int j;
 
-	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-		clk_disable(bank->dbck);
-
 	if (!bank->mod_usage)
 		return 0;
 
@@ -1192,6 +1191,16 @@ update_gpio_context_count:
 		bank->context_loss_count =
 				bank->get_context_loss_count(bank->dev);
 
+	if (bank->dbck_enable_mask) {
+		bank->context.debounce = __raw_readl(bank->base +
+						bank->regs->debounce);
+		bank->context.debounce_en = __raw_readl(bank->base +
+						bank->regs->debounce_en);
+	}
+
+	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
+		clk_disable(bank->dbck);
+
 	return 0;
 }
 
@@ -1331,6 +1340,13 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+
+	if (bank->dbck_enable_mask) {
+		__raw_writel(bank->context.debounce, bank->base +
+					bank->regs->debounce);
+		__raw_writel(bank->context.debounce_en,
+					bank->base + bank->regs->debounce_en);
+	}
 }
 #else
 #define omap_gpio_runtime_suspend NULL
Signature · 1 line
1.7.0.4
#37 lore raw

PATCH v6 22/25 gpio/omap: save and restore debounce registers

Quoted 1 line · Tarun Kanti DebBarma

From: Nishant Menon <[email protected]>

Check spelling of first name (I believe version in signed-off-by below is the correct one.)

Quoted 35 lines

GPIO debounce registers need to be saved and restored for proper functioning of driver. To save the registers, we cannot cut the clock before the save, hence move the clk disable after the save.

---
 drivers/gpio/gpio-omap.c |   22 +++++++++++++++++++---
 1 files changed, 19 insertions(+), 3 deletions(-)
drivers/gpio/gpio-omap.c +2 -3
index dc382f6..67e08e9 100644
@@ -41,6 +41,8 @@ struct gpio_regs {
 	u32 risingdetect;
 	u32 fallingdetect;
 	u32 dataout;
+	u32 debounce;
+	u32 debounce_en;
 };
 
 struct gpio_bank {
@@ -1158,9 +1160,6 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 	u32 l1 = 0, l2 = 0;
 	int j;
 
-	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
-		clk_disable(bank->dbck);
-
 	if (!bank->mod_usage)
 		return 0;
 

drivers/gpio/gpio-omap.c update_gpio_context_count: · line 1198

Quoted 8 lines
drivers/gpio/gpio-omap.c +5 -0
@@ -1192,6 +1191,16 @@ update_gpio_context_count:
 		bank->context_loss_count =
 				bank->get_context_loss_count(bank->dev);
 
+	if (bank->dbck_enable_mask) {
+		bank->context.debounce = __raw_readl(bank->base +
+						bank->regs->debounce);
+		bank->context.debounce_en = __raw_readl(bank->base +
+						bank->regs->debounce_en);

Here you're taking a step backwards from the goal of not having to read registers in the runtime suspend callback.

Rather than reading the registers here, the values should be saved into bank->context when they are initially written (_set_gpio_debounce()), so you don't have the overhead of reading the registers in ->runtime_suspend.

Quoted 12 lines
drivers/gpio/gpio-omap.c +5 -0
+	}
+
+	for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
+		clk_disable(bank->dbck);
+
 	return 0;
 }
 
@@ -1331,6 +1340,13 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1352

Quoted 10 lines
drivers/gpio/gpio-omap.c +7 -0
+
+	if (bank->dbck_enable_mask) {
+		__raw_writel(bank->context.debounce, bank->base +
+					bank->regs->debounce);
+		__raw_writel(bank->context.debounce_en,
+					bank->base + bank->regs->debounce_en);
+	}
 }
 #else
 #define omap_gpio_runtime_suspend NULL

Kevin

#38 lore raw

PATCH v6 22/25 gpio/omap: save and restore debounce registers

Quoted 6 lines · Kevin Hilman
Quoted 1 line · Tarun Kanti DebBarma

From: Nishant Menon <[email protected]>

Check spelling of first name (I believe version in signed-off-by below is the correct one.)

Yes, it should haven been "Nishanth".

Quoted 48 lines
Quoted 39 lines

GPIO debounce registers need to be saved and restored for proper functioning of driver. To save the registers, we cannot cut the clock before the save, hence move the clk disable after the save.

---
?drivers/gpio/gpio-omap.c | ? 22 +++++++++++++++++++--- ?1 files changed, 19 insertions(+), 3 deletions(-)

drivers/gpio/gpio-omap.c +2 -3
index dc382f6..67e08e9 100644
@@ -41,6 +41,8 @@ struct gpio_regs {
 ? ? ? u32 risingdetect;
 ? ? ? u32 fallingdetect;
 ? ? ? u32 dataout;
+ ? ? u32 debounce;
+ ? ? u32 debounce_en;
 ?};
 
 ?struct gpio_bank {
@@ -1158,9 +1160,6 @@ static int omap_gpio_runtime_suspend(struct device *dev)
 ? ? ? u32 l1 = 0, l2 = 0;
 ? ? ? int j;
 
- ? ? for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
- ? ? ? ? ? ? clk_disable(bank->dbck);
-
 ? ? ? if (!bank->mod_usage)
 ? ? ? ? ? ? ? return 0;
 
@@ -1192,6 +1191,16 @@ update_gpio_context_count:

? ? ? ? ? ? ? bank->context_loss_count =
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->get_context_loss_count(bank->dev);

Quoted 5 lines

+ ? ? if (bank->dbck_enable_mask) {
+ ? ? ? ? ? ? bank->context.debounce = __raw_readl(bank->base +
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->regs->debounce);
+ ? ? ? ? ? ? bank->context.debounce_en = __raw_readl(bank->base +
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->regs->debounce_en);

Here you're taking a step backwards from the goal of not having to read registers in the runtime suspend callback.

Quoted 3 lines

Rather than reading the registers here, the values should be saved into bank->context when they are initially written (_set_gpio_debounce()), so you don't have the overhead of reading the registers in ->runtime_suspend.

Good catch! Thanks.
--
Tarun

Quoted 26 lines
Quoted 21 lines

+ ? ? }

drivers/gpio/gpio-omap.c +4 -0
+
+ ? ? for (j = 0; j < hweight_long(bank->dbck_enable_mask); j++)
+ ? ? ? ? ? ? clk_disable(bank->dbck);
+

? ? ? return 0;
?}

drivers/gpio/gpio-omap.c +7 -0
@@ -1331,6 +1340,13 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ? ? ? __raw_writel(bank->context.fallingdetect,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->fallingdetect);
 ? ? ? __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+
+ ? ? if (bank->dbck_enable_mask) {
+ ? ? ? ? ? ? __raw_writel(bank->context.debounce, bank->base +
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->regs->debounce);
+ ? ? ? ? ? ? __raw_writel(bank->context.debounce_en,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->debounce_en);
+ ? ? }
 ?}
Quoted 2 lines

?#else
?#define omap_gpio_runtime_suspend NULL

Kevin

#39 lore raw

PATCH v6 23/25 gpio/omap: enable irq at the end of all configuration in restore

In reply to Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

Setup the interrupt enable registers only after we have configured the required edge and required configurations, not before, to prevent spurious events as part of restore routine.

---
 drivers/gpio/gpio-omap.c |    8 ++++----
 1 files changed, 4 insertions(+), 4 deletions(-)
drivers/gpio/gpio-omap.c +4 -4
index 67e08e9..db22df8 100644
@@ -1323,10 +1323,6 @@ void omap2_gpio_resume_after_idle(void)
 
 static void omap_gpio_restore_context(struct gpio_bank *bank)
 {
-	__raw_writel(bank->context.irqenable1,
-				bank->base + bank->regs->irqenable);
-	__raw_writel(bank->context.irqenable2,
-				bank->base + bank->regs->irqenable2);
 	__raw_writel(bank->context.wake_en,
 				bank->base + bank->regs->wkup_en);
 	__raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
@@ -1347,6 +1343,10 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 		__raw_writel(bank->context.debounce_en,
 					bank->base + bank->regs->debounce_en);
 	}
+	__raw_writel(bank->context.irqenable1,
+				bank->base + bank->regs->irqenable);
+	__raw_writel(bank->context.irqenable2,
+				bank->base + bank->regs->irqenable2);
 }
 #else
 #define omap_gpio_runtime_suspend NULL
Signature · 1 line
1.7.0.4
#40 lore raw

PATCH v6 23/25 gpio/omap: enable irq at the end of all configuration in restore

Quoted 9 lines · Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

Setup the interrupt enable registers only after we have configured the required edge and required configurations, not before, to prevent spurious events as part of restore routine.

Good catch Nishanth.

Kevin

#41 lore raw

PATCH v6 24/25 gpio/omap: restore OE only after setting the output level

In reply to Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

Setup the dataout register before setting the GPIO to output mode in restore path.

---
 drivers/gpio/gpio-omap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/gpio/gpio-omap.c +1 -1
index db22df8..a629498 100644
@@ -1326,7 +1326,6 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.wake_en,
 				bank->base + bank->regs->wkup_en);
 	__raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
-	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 	__raw_writel(bank->context.leveldetect0,
 				bank->base + bank->regs->leveldetect0);
 	__raw_writel(bank->context.leveldetect1,
@@ -1336,6 +1335,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 	if (bank->dbck_enable_mask) {
 		__raw_writel(bank->context.debounce, bank->base +
Signature · 1 line
1.7.0.4
#42 lore raw

PATCH v6 24/25 gpio/omap: restore OE only after setting the output level

Quoted 4 lines · Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

Setup the dataout register before setting the GPIO to output mode in restore path.

Please summarize why. (again, it may seem obvious now, but may not be for those not familiar with the driver or when coming back to it after a few months looking at other code.

Kevin

Quoted 27 lines
---
 drivers/gpio/gpio-omap.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/gpio/gpio-omap.c +1 -1
index db22df8..a629498 100644
@@ -1326,7 +1326,6 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.wake_en,
 				bank->base + bank->regs->wkup_en);
 	__raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
-	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 	__raw_writel(bank->context.leveldetect0,
 				bank->base + bank->regs->leveldetect0);
 	__raw_writel(bank->context.leveldetect1,
@@ -1336,6 +1335,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
 	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 	if (bank->dbck_enable_mask) {
 		__raw_writel(bank->context.debounce, bank->base +
#43 lore raw

PATCH v6 24/25 gpio/omap: restore OE only after setting the output level

Quoted 10 lines · Kevin Hilman
Quoted 4 lines · Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

Setup the dataout register before setting the GPIO to output mode in restore path.

Please summarize why. ?(again, it may seem obvious now, but may not be for those not familiar with the driver or when coming back to it after a few months looking at other code.

Ok.

Quoted 31 lines

Kevin

Quoted 27 lines

---
?drivers/gpio/gpio-omap.c | ? ?2 +-
?1 files changed, 1 insertions(+), 1 deletions(-)

drivers/gpio/gpio-omap.c +1 -1
index db22df8..a629498 100644
@@ -1326,7 +1326,6 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ? ? ? __raw_writel(bank->context.wake_en,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->wkup_en);
 ? ? ? __raw_writel(bank->context.ctrl, bank->base + bank->regs->ctrl);
- ? ? __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 ? ? ? __raw_writel(bank->context.leveldetect0,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->leveldetect0);
 ? ? ? __raw_writel(bank->context.leveldetect1,
@@ -1336,6 +1335,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ? ? ? __raw_writel(bank->context.fallingdetect,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->fallingdetect);
 ? ? ? __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+ ? ? __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 ? ? ? if (bank->dbck_enable_mask) {

? ? ? ? ? ? ? __raw_writel(bank->context.debounce, bank->base +

#44 lore raw

PATCH v6 25/25 gpio/omap: handle set_dataout reg capable IP on restore

In reply to Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

GPIO IP revisions such as those used in OMAP4 have a set_dataout while the previous revisions used a single dataout register. Depending on what is available restore the dataout settings to the right register.

---
 drivers/gpio/gpio-omap.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)
drivers/gpio/gpio-omap.c +6 -1
index a629498..4680b4c 100644
@@ -1334,7 +1334,12 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 				bank->base + bank->regs->risingdetect);
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
-	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+	if (bank->regs->set_dataout && bank->regs->clr_dataout)
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->set_dataout);
+	else
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->dataout);
 	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 	if (bank->dbck_enable_mask) {
Signature · 1 line
1.7.0.4
#45 lore raw

PATCH v6 25/25 gpio/omap: handle set_dataout reg capable IP on restore

Quoted 6 lines · Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

GPIO IP revisions such as those used in OMAP4 have a set_dataout while the previous revisions used a single dataout register. Depending on what is available restore the dataout settings to the right register.

OK, minor nit below...

Quoted 12 lines
---
 drivers/gpio/gpio-omap.c |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)
drivers/gpio/gpio-omap.c +0 -0
index a629498..4680b4c 100644

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1337

Quoted 5 lines
drivers/gpio/gpio-omap.c +1 -1
@@ -1334,7 +1334,12 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 				bank->base + bank->regs->risingdetect);
 	__raw_writel(bank->context.fallingdetect,
 				bank->base + bank->regs->fallingdetect);
-	__raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+	if (bank->regs->set_dataout && bank->regs->clr_dataout)

Why the check for ->clr_dataout here?

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1345

Quoted 8 lines
drivers/gpio/gpio-omap.c +5 -0
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->set_dataout);
+	else
+		__raw_writel(bank->context.dataout,
+				bank->base + bank->regs->dataout);
 	__raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 	if (bank->dbck_enable_mask) {

Kevin

#46 lore raw

PATCH v6 25/25 gpio/omap: handle set_dataout reg capable IP on restore

Quoted 18 lines · Kevin Hilman
Quoted 6 lines · Tarun Kanti DebBarma

From: Nishanth Menon <[email protected]>

GPIO IP revisions such as those used in OMAP4 have a set_dataout while the previous revisions used a single dataout register. Depending on what is available restore the dataout settings to the right register.

OK, minor nit below...

Quoted 7 lines

---
?drivers/gpio/gpio-omap.c | ? ?7 ++++++-
?1 files changed, 6 insertions(+), 1 deletions(-)

Quoted 12 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1337

Quoted 10 lines
drivers/gpio/gpio-omap.c +1 -1
index a629498..4680b4c 100644
@@ -1334,7 +1334,12 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->risingdetect);
 ? ? ? __raw_writel(bank->context.fallingdetect,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->fallingdetect);
- ? ? __raw_writel(bank->context.dataout, bank->base + bank->regs->dataout);
+ ? ? if (bank->regs->set_dataout && bank->regs->clr_dataout)

Why the check for ->clr_dataout here?

Well, I guess it was just an additional check. It can possibly be removed. --
Tarun

Quoted 12 lines

drivers/gpio/gpio-omap.c static void omap_gpio_restore_context(struct gpio_bank *bank) · line 1345

Quoted 9 lines
drivers/gpio/gpio-omap.c +5 -0
+ ? ? ? ? ? ? __raw_writel(bank->context.dataout,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->set_dataout);
+ ? ? else
+ ? ? ? ? ? ? __raw_writel(bank->context.dataout,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? bank->base + bank->regs->dataout);
 ? ? ? __raw_writel(bank->context.oe, bank->base + bank->regs->direction);
 
 ? ? ? if (bank->dbck_enable_mask) {

Kevin

#47 lore raw

v6 cover gpio/omap: driver cleanup and fixes

In reply to Tarun Kanti DebBarma

Hi Tarun,

Quoted 5 lines · Tarun Kanti DebBarma

This series is continuation of cleanup of OMAP GPIO driver and fixes. The cleanup include getting rid of cpu_is_* checks wherever possible, use of gpio_bank list instead of static array, use of unique platform specific value associated data member to OMAP platforms to avoid cpu_is_* checks. The series also include PM runtime support.*

Thanks for your continued effort on this series.

Quoted 3 lines

Baseline: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Branch: master
Commit: c6a389f Linux 3.1-rc4

This series was supposed to be based on my for_3.2/gpio-cleanup branch, which removes MOD_REG_BIT among other things.

Please rebase onto that branch so these changes can be tested along with changes already queued for v3.2.

Thanks,

Kevin

#48 lore raw

v6 cover gpio/omap: driver cleanup and fixes

Quoted 10 lines · Kevin Hilman

Hi Tarun,

Quoted 5 lines · Tarun Kanti DebBarma

This series is continuation of cleanup of OMAP GPIO driver and fixes. The cleanup include getting rid of cpu_is_* checks wherever possible, use of gpio_bank list instead of static array, use of unique platform specific value associated data member to OMAP platforms to avoid cpu_is_* checks. The series also include PM runtime support.*

Quoted 8 lines

Thanks for your continued effort on this series.

Quoted 3 lines

Baseline: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Branch: master
Commit: c6a389f ?Linux 3.1-rc4

This series was supposed to be based on my for_3.2/gpio-cleanup branch, which removes MOD_REG_BIT among other things.

I saw most of your patches on the mainline except MOD_REG_BIT. I thought you have no intention of taking it. That's why generated the series on the mainline.

Quoted 3 lines

Please rebase onto that branch so these changes can be tested along with changes already queued for v3.2.

Ok.

Quoted 5 lines

Thanks,

Kevin

#49 lore raw

v6 cover gpio/omap: driver cleanup and fixes

[...]

Quoted 3 lines
Quoted 2 lines

Please rebase onto that branch so these changes can be tested along with changes already queued for v3.2.

Ok.

I am not able to git pull
git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git
Looks like there is problem with git.kernel.org?
--
Tarun

Quoted 1 line

[...]

#50 lore raw

v6 cover gpio/omap: driver cleanup and fixes

Quoted 7 lines · Tarun Kanti

[...]

Quoted 3 lines
Quoted 2 lines

Please rebase onto that branch so these changes can be tested along with changes already queued for v3.2.

Ok.

I am not able to git pull
git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git
Looks like there is problem with git.kernel.org?

Yes - the main kernel.org server went down a week and a half ago due to being cracked. They notified the authorities and have been working to analyze the intrusion, as well as verifying the considerable amount of user data that they hold.

That wasn't too much of a problem (trees can be hosted elsewhere), but it was followed a week later by the kernel.org DNS servers, which took out access to things like git.kernel.org. As mailing lists (such as linux-omap) are hosted on vger.kernel.org, steps were taken to restore some of the DNS so the mailing lists would continue working, but without the master server the remainder of the DNS is still off-line.

#51 lore raw

v6 cover gpio/omap: driver cleanup and fixes

In reply to DebBarma, Tarun Kanti
Quoted 7 lines · Tarun Kanti

[...]

Quoted 3 lines
Quoted 2 lines

Please rebase onto that branch so these changes can be tested along with changes already queued for v3.2.

Ok.

I am not able to git pull
git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-omap-pm.git
Looks like there is problem with git.kernel.org?

Until the kernel.org infrastructure has recovered, you can use my backup tree from gitorious[1]. The for_3.2/gpio-cleanup branch is available there.

Kevin

[1] git://gitorious.org/khilman/linux-omap-pm.git

#52 lore raw

v6 cover gpio/omap: driver cleanup and fixes

In reply to Tarun Kanti DebBarma

Hi Tarun,

Quoted 5 lines · Tarun Kanti DebBarma

This series is continuation of cleanup of OMAP GPIO driver and fixes. The cleanup include getting rid of cpu_is_* checks wherever possible, use of gpio_bank list instead of static array, use of unique platform specific value associated data member to OMAP platforms to avoid cpu_is_* checks. The series also include PM runtime support.*

I tested this series on top of v3.1-rc4 using a 3430/n900 platform.

During suspend the PER powerdomain does not hit the targetted power state. Also, in idle PER never hits retention.

As with previous versions of this series, it appears to be related to debounce clocks being left enabled. On my n900, I removed debounce from all the GPIO keys pads and PER was then able to hit retention during suspend and idle.

Please be sure to test on a platform that is using debounce, or modify the board file for one of the platforms your testing so that at least one of the GPIOs has debounce enabled so you are verifying the debounce clock gating during suspend and idle.

Thanks,

Kevin

#53 lore raw

v6 cover gpio/omap: driver cleanup and fixes

Quoted 12 lines · Kevin Hilman

Hi Tarun,

Quoted 5 lines · Tarun Kanti DebBarma

This series is continuation of cleanup of OMAP GPIO driver and fixes. The cleanup include getting rid of cpu_is_* checks wherever possible, use of gpio_bank list instead of static array, use of unique platform specific value associated data member to OMAP platforms to avoid cpu_is_* checks. The series also include PM runtime support.*

I tested this series on top of v3.1-rc4 using a 3430/n900 platform.

Quoted 7 lines

During suspend the PER powerdomain does not hit the targetted power state. ?Also, in idle PER never hits retention.

As with previous versions of this series, it appears to be related to debounce clocks being left enabled. ?On my n900, I removed debounce from all the GPIO keys pads and PER was then able to hit retention during suspend and idle.

In this series the debounce clock is turned off and it should have worked.

Quoted 5 lines

Please be sure to test on a platform that is using debounce, or modify the board file for one of the platforms your testing so that at least one of the GPIOs has debounce enabled so you are verifying the debounce clock gating during suspend and idle.

Yes, I will setup a system for testing debounce clock gating.

Quoted 8 lines

Thanks,

Kevin

#54 lore raw

v6 cover gpio/omap: driver cleanup and fixes

In reply to Kevin Hilman

[...]

Quoted 10 lines

I tested this series on top of v3.1-rc4 using a 3430/n900 platform.

During suspend the PER powerdomain does not hit the targetted power state. ?Also, in idle PER never hits retention.

As with previous versions of this series, it appears to be related to debounce clocks being left enabled. ?On my n900, I removed debounce from all the GPIO keys pads and PER was then able to hit retention during suspend and idle.

Quoted 4 lines

Please be sure to test on a platform that is using debounce, or modify the board file for one of the platforms your testing so that at least one of the GPIOs has debounce enabled so you are verifying the debounce clock gating during suspend and idle.

I was able to re-produce the problem by making explicit call to _set_gpio_debounce() in *_mod_init().
Prior to calling this I initialized: bank->dbck = clk_get(bank->dev, "dbclk"); as in the function below.
Later I realized that there is no alias associated with "dbclk" for GPIO[2-6].

static int gpio_debounce(struct gpio_chip *chip, unsigned offset,
unsigned debounce)
{
...

        if (!bank->dbck) {
                bank->dbck = clk_get(bank->dev, "dbclk");
...
        }

After incorporating the following alias I was able to put system to OFF.

static struct omap_clk omap3xxx_clks[] = {
...

        CLK("omap_gpio.6",       "dbclk",   &gpio6_dbck,    CK_3XXX),
        CLK("omap_gpio.5",       "dbclk",   &gpio5_dbck,    CK_3XXX),
        CLK("omap_gpio.4",       "dbclk",   &gpio4_dbck,    CK_3XXX),
        CLK("omap_gpio.3",       "dbclk",   &gpio3_dbck,    CK_3XXX),
        CLK("omap_gpio.2",       "dbclk",   &gpio2_dbck,    CK_3XXX),

--
Tarun

Quoted 5 lines

Thanks,

Kevin