forked from mirrors/linux
		
	gpio/omap: ensure gpio context is initialised
Commit a2797be (gpio/omap: force restore if context loss is not
detectable) broke gpio support for OMAP when booting with device-tree
because a restore of the gpio context being performed without ever
initialising the gpio context. In other words, the context restored was
bad.
This problem could also occur in the non device-tree case, however, it
is much less likely because when booting without device-tree we can
detect context loss via a platform specific API and so context restore
is performed less often.
Nevertheless we should ensure that the gpio context is initialised
on the first pm-runtime resume for gpio banks that could lose their
state regardless of whether we are booting with device-tree or not.
The context loss count was being initialised on the first pm-runtime
suspend following a resume, by populating the get_count_loss_count()
function pointer after the first pm-runtime resume. To make the code
more readable and logical, initialise the context loss count on the
first pm-runtime resume if the context is not yet valid.
Reported-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Acked-by: Santosh Shilimkar<santosh.shilimkar@ti.com>
Reviewed-by: Kevin Hilman <khilman@linaro.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
			
			
This commit is contained in:
		
							parent
							
								
									f722406faa
								
							
						
					
					
						commit
						352a2d5bfc
					
				
					 1 changed files with 45 additions and 3 deletions
				
			
		|  | @ -69,6 +69,7 @@ struct gpio_bank { | ||||||
| 	bool is_mpuio; | 	bool is_mpuio; | ||||||
| 	bool dbck_flag; | 	bool dbck_flag; | ||||||
| 	bool loses_context; | 	bool loses_context; | ||||||
|  | 	bool context_valid; | ||||||
| 	int stride; | 	int stride; | ||||||
| 	u32 width; | 	u32 width; | ||||||
| 	int context_loss_count; | 	int context_loss_count; | ||||||
|  | @ -1128,6 +1129,10 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 			bank->loses_context = true; | 			bank->loses_context = true; | ||||||
| 	} else { | 	} else { | ||||||
| 		bank->loses_context = pdata->loses_context; | 		bank->loses_context = pdata->loses_context; | ||||||
|  | 
 | ||||||
|  | 		if (bank->loses_context) | ||||||
|  | 			bank->get_context_loss_count = | ||||||
|  | 				pdata->get_context_loss_count; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -1178,9 +1183,6 @@ static int omap_gpio_probe(struct platform_device *pdev) | ||||||
| 	omap_gpio_chip_init(bank); | 	omap_gpio_chip_init(bank); | ||||||
| 	omap_gpio_show_rev(bank); | 	omap_gpio_show_rev(bank); | ||||||
| 
 | 
 | ||||||
| 	if (bank->loses_context) |  | ||||||
| 		bank->get_context_loss_count = pdata->get_context_loss_count; |  | ||||||
| 
 |  | ||||||
| 	pm_runtime_put(bank->dev); | 	pm_runtime_put(bank->dev); | ||||||
| 
 | 
 | ||||||
| 	list_add_tail(&bank->node, &omap_gpio_list); | 	list_add_tail(&bank->node, &omap_gpio_list); | ||||||
|  | @ -1259,6 +1261,8 @@ static int omap_gpio_runtime_suspend(struct device *dev) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void omap_gpio_init_context(struct gpio_bank *p); | ||||||
|  | 
 | ||||||
| static int omap_gpio_runtime_resume(struct device *dev) | static int omap_gpio_runtime_resume(struct device *dev) | ||||||
| { | { | ||||||
| 	struct platform_device *pdev = to_platform_device(dev); | 	struct platform_device *pdev = to_platform_device(dev); | ||||||
|  | @ -1268,6 +1272,20 @@ static int omap_gpio_runtime_resume(struct device *dev) | ||||||
| 	int c; | 	int c; | ||||||
| 
 | 
 | ||||||
| 	spin_lock_irqsave(&bank->lock, flags); | 	spin_lock_irqsave(&bank->lock, flags); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * On the first resume during the probe, the context has not | ||||||
|  | 	 * been initialised and so initialise it now. Also initialise | ||||||
|  | 	 * the context loss count. | ||||||
|  | 	 */ | ||||||
|  | 	if (bank->loses_context && !bank->context_valid) { | ||||||
|  | 		omap_gpio_init_context(bank); | ||||||
|  | 
 | ||||||
|  | 		if (bank->get_context_loss_count) | ||||||
|  | 			bank->context_loss_count = | ||||||
|  | 				bank->get_context_loss_count(bank->dev); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	_gpio_dbck_enable(bank); | 	_gpio_dbck_enable(bank); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | @ -1384,6 +1402,29 @@ void omap2_gpio_resume_after_idle(void) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #if defined(CONFIG_PM_RUNTIME) | #if defined(CONFIG_PM_RUNTIME) | ||||||
|  | static void omap_gpio_init_context(struct gpio_bank *p) | ||||||
|  | { | ||||||
|  | 	struct omap_gpio_reg_offs *regs = p->regs; | ||||||
|  | 	void __iomem *base = p->base; | ||||||
|  | 
 | ||||||
|  | 	p->context.ctrl		= __raw_readl(base + regs->ctrl); | ||||||
|  | 	p->context.oe		= __raw_readl(base + regs->direction); | ||||||
|  | 	p->context.wake_en	= __raw_readl(base + regs->wkup_en); | ||||||
|  | 	p->context.leveldetect0	= __raw_readl(base + regs->leveldetect0); | ||||||
|  | 	p->context.leveldetect1	= __raw_readl(base + regs->leveldetect1); | ||||||
|  | 	p->context.risingdetect	= __raw_readl(base + regs->risingdetect); | ||||||
|  | 	p->context.fallingdetect = __raw_readl(base + regs->fallingdetect); | ||||||
|  | 	p->context.irqenable1	= __raw_readl(base + regs->irqenable); | ||||||
|  | 	p->context.irqenable2	= __raw_readl(base + regs->irqenable2); | ||||||
|  | 
 | ||||||
|  | 	if (regs->set_dataout && p->regs->clr_dataout) | ||||||
|  | 		p->context.dataout = __raw_readl(base + regs->set_dataout); | ||||||
|  | 	else | ||||||
|  | 		p->context.dataout = __raw_readl(base + regs->dataout); | ||||||
|  | 
 | ||||||
|  | 	p->context_valid = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void omap_gpio_restore_context(struct gpio_bank *bank) | static void omap_gpio_restore_context(struct gpio_bank *bank) | ||||||
| { | { | ||||||
| 	__raw_writel(bank->context.wake_en, | 	__raw_writel(bank->context.wake_en, | ||||||
|  | @ -1421,6 +1462,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank) | ||||||
| #else | #else | ||||||
| #define omap_gpio_runtime_suspend NULL | #define omap_gpio_runtime_suspend NULL | ||||||
| #define omap_gpio_runtime_resume NULL | #define omap_gpio_runtime_resume NULL | ||||||
|  | static void omap_gpio_init_context(struct gpio_bank *p) {} | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static const struct dev_pm_ops gpio_pm_ops = { | static const struct dev_pm_ops gpio_pm_ops = { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Jon Hunter
						Jon Hunter