Commit 352a2d5b authored by Jon Hunter's avatar Jon Hunter Committed by Linus Walleij

gpio/omap: ensure gpio context is initialised

Commit a2797bea (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: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarJon Hunter <jon-hunter@ti.com>
Acked-by: Santosh Shilimkar<santosh.shilimkar@ti.com>
Reviewed-by: default avatarKevin Hilman <khilman@linaro.org>
Tested-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent f722406f
...@@ -69,6 +69,7 @@ struct gpio_bank { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment