Commit 7ccbc60c authored by Tomasz Figa's avatar Tomasz Figa Committed by Linus Walleij

pinctrl: exynos: Handle suspend/resume of GPIO EINT registers

Some GPIO EINT control registers needs to be preserved across
suspend/resume cycle. This patch extends the driver to take care of
this.
Signed-off-by: default avatarTomasz Figa <t.figa@samsung.com>
Signed-off-by: default avatarKyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 3385474c
...@@ -196,6 +196,12 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data) ...@@ -196,6 +196,12 @@ static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
struct exynos_eint_gpio_save {
u32 eint_con;
u32 eint_fltcon0;
u32 eint_fltcon1;
};
/* /*
* exynos_eint_gpio_init() - setup handling of external gpio interrupts. * exynos_eint_gpio_init() - setup handling of external gpio interrupts.
* @d: driver data of samsung pinctrl driver. * @d: driver data of samsung pinctrl driver.
...@@ -204,8 +210,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) ...@@ -204,8 +210,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
{ {
struct samsung_pin_bank *bank; struct samsung_pin_bank *bank;
struct device *dev = d->dev; struct device *dev = d->dev;
unsigned int ret; int ret;
unsigned int i; int i;
if (!d->irq) { if (!d->irq) {
dev_err(dev, "irq number not available\n"); dev_err(dev, "irq number not available\n");
...@@ -227,11 +233,29 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d) ...@@ -227,11 +233,29 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
bank->nr_pins, &exynos_gpio_irqd_ops, bank); bank->nr_pins, &exynos_gpio_irqd_ops, bank);
if (!bank->irq_domain) { if (!bank->irq_domain) {
dev_err(dev, "gpio irq domain add failed\n"); dev_err(dev, "gpio irq domain add failed\n");
return -ENXIO; ret = -ENXIO;
goto err_domains;
}
bank->soc_priv = devm_kzalloc(d->dev,
sizeof(struct exynos_eint_gpio_save), GFP_KERNEL);
if (!bank->soc_priv) {
irq_domain_remove(bank->irq_domain);
ret = -ENOMEM;
goto err_domains;
} }
} }
return 0; return 0;
err_domains:
for (--i, --bank; i >= 0; --i, --bank) {
if (bank->eint_type != EINT_TYPE_GPIO)
continue;
irq_domain_remove(bank->irq_domain);
}
return ret;
} }
static void exynos_wkup_irq_unmask(struct irq_data *irqd) static void exynos_wkup_irq_unmask(struct irq_data *irqd)
...@@ -528,6 +552,72 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) ...@@ -528,6 +552,72 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
return 0; return 0;
} }
static void exynos_pinctrl_suspend_bank(
struct samsung_pinctrl_drv_data *drvdata,
struct samsung_pin_bank *bank)
{
struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = drvdata->virt_base;
save->eint_con = readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset);
save->eint_fltcon0 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset);
save->eint_fltcon1 = readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset + 4);
pr_debug("%s: save con %#010x\n", bank->name, save->eint_con);
pr_debug("%s: save fltcon0 %#010x\n", bank->name, save->eint_fltcon0);
pr_debug("%s: save fltcon1 %#010x\n", bank->name, save->eint_fltcon1);
}
static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
struct samsung_pin_bank *bank = ctrl->pin_banks;
int i;
for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
if (bank->eint_type == EINT_TYPE_GPIO)
exynos_pinctrl_suspend_bank(drvdata, bank);
}
static void exynos_pinctrl_resume_bank(
struct samsung_pinctrl_drv_data *drvdata,
struct samsung_pin_bank *bank)
{
struct exynos_eint_gpio_save *save = bank->soc_priv;
void __iomem *regs = drvdata->virt_base;
pr_debug("%s: con %#010x => %#010x\n", bank->name,
readl(regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset), save->eint_con);
pr_debug("%s: fltcon0 %#010x => %#010x\n", bank->name,
readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset), save->eint_fltcon0);
pr_debug("%s: fltcon1 %#010x => %#010x\n", bank->name,
readl(regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset + 4), save->eint_fltcon1);
writel(save->eint_con, regs + EXYNOS_GPIO_ECON_OFFSET
+ bank->eint_offset);
writel(save->eint_fltcon0, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset);
writel(save->eint_fltcon1, regs + EXYNOS_GPIO_EFLTCON_OFFSET
+ 2 * bank->eint_offset + 4);
}
static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
{
struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
struct samsung_pin_bank *bank = ctrl->pin_banks;
int i;
for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
if (bank->eint_type == EINT_TYPE_GPIO)
exynos_pinctrl_resume_bank(drvdata, bank);
}
/* pin banks of exynos4210 pin-controller 0 */ /* pin banks of exynos4210 pin-controller 0 */
static struct samsung_pin_bank exynos4210_pin_banks0[] = { static struct samsung_pin_bank exynos4210_pin_banks0[] = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00), EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
...@@ -591,6 +681,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { ...@@ -591,6 +681,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4210-gpio-ctrl0", .label = "exynos4210-gpio-ctrl0",
}, { }, {
/* pin-controller instance 1 data */ /* pin-controller instance 1 data */
...@@ -605,6 +697,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = { ...@@ -605,6 +697,8 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init, .eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4210-gpio-ctrl1", .label = "exynos4210-gpio-ctrl1",
}, { }, {
/* pin-controller instance 2 data */ /* pin-controller instance 2 data */
...@@ -686,6 +780,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { ...@@ -686,6 +780,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl0", .label = "exynos4x12-gpio-ctrl0",
}, { }, {
/* pin-controller instance 1 data */ /* pin-controller instance 1 data */
...@@ -700,6 +796,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { ...@@ -700,6 +796,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init, .eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl1", .label = "exynos4x12-gpio-ctrl1",
}, { }, {
/* pin-controller instance 2 data */ /* pin-controller instance 2 data */
...@@ -710,6 +808,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { ...@@ -710,6 +808,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl2", .label = "exynos4x12-gpio-ctrl2",
}, { }, {
/* pin-controller instance 3 data */ /* pin-controller instance 3 data */
...@@ -720,6 +820,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = { ...@@ -720,6 +820,8 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos4x12-gpio-ctrl3", .label = "exynos4x12-gpio-ctrl3",
}, },
}; };
...@@ -798,6 +900,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { ...@@ -798,6 +900,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init, .eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl0", .label = "exynos5250-gpio-ctrl0",
}, { }, {
/* pin-controller instance 1 data */ /* pin-controller instance 1 data */
...@@ -808,6 +912,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { ...@@ -808,6 +912,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl1", .label = "exynos5250-gpio-ctrl1",
}, { }, {
/* pin-controller instance 2 data */ /* pin-controller instance 2 data */
...@@ -818,6 +924,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { ...@@ -818,6 +924,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl2", .label = "exynos5250-gpio-ctrl2",
}, { }, {
/* pin-controller instance 3 data */ /* pin-controller instance 3 data */
...@@ -828,6 +936,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = { ...@@ -828,6 +936,8 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.geint_pend = EXYNOS_GPIO_EPEND_OFFSET, .geint_pend = EXYNOS_GPIO_EPEND_OFFSET,
.svc = EXYNOS_SVC_OFFSET, .svc = EXYNOS_SVC_OFFSET,
.eint_gpio_init = exynos_eint_gpio_init, .eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
.label = "exynos5250-gpio-ctrl3", .label = "exynos5250-gpio-ctrl3",
}, },
}; };
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
/* External GPIO and wakeup interrupt related definitions */ /* External GPIO and wakeup interrupt related definitions */
#define EXYNOS_GPIO_ECON_OFFSET 0x700 #define EXYNOS_GPIO_ECON_OFFSET 0x700
#define EXYNOS_GPIO_EFLTCON_OFFSET 0x800
#define EXYNOS_GPIO_EMASK_OFFSET 0x900 #define EXYNOS_GPIO_EMASK_OFFSET 0x900
#define EXYNOS_GPIO_EPEND_OFFSET 0xA00 #define EXYNOS_GPIO_EPEND_OFFSET 0xA00
#define EXYNOS_WKUP_ECON_OFFSET 0xE00 #define EXYNOS_WKUP_ECON_OFFSET 0xE00
......
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