aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch')
-rw-r--r--target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch137
1 files changed, 137 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch b/target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch
new file mode 100644
index 0000000..9ef1815
--- /dev/null
+++ b/target/linux/mvebu/patches-3.18/198-gpio_mvebu_suspend.patch
@@ -0,0 +1,137 @@
+This commit adds the implementation of ->suspend() and ->resume()
+platform_driver hooks in order to save and restore the state of the
+GPIO configuration. In order to achieve that, additional fields are
+added to the mvebu_gpio_chip structure.
+
+Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+Acked-by: Alexandre Courbot <acourbot@nvidia.com>
+Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
+
+--- a/drivers/gpio/gpio-mvebu.c
++++ b/drivers/gpio/gpio-mvebu.c
+@@ -83,6 +83,14 @@ struct mvebu_gpio_chip {
+ int irqbase;
+ struct irq_domain *domain;
+ int soc_variant;
++
++ /* Used to preserve GPIO registers accross suspend/resume */
++ u32 out_reg;
++ u32 io_conf_reg;
++ u32 blink_en_reg;
++ u32 in_pol_reg;
++ u32 edge_mask_regs[4];
++ u32 level_mask_regs[4];
+ };
+
+ /*
+@@ -562,6 +570,93 @@ static const struct of_device_id mvebu_g
+ };
+ MODULE_DEVICE_TABLE(of, mvebu_gpio_of_match);
+
++static int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state)
++{
++ struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
++ int i;
++
++ mvchip->out_reg = readl(mvebu_gpioreg_out(mvchip));
++ mvchip->io_conf_reg = readl(mvebu_gpioreg_io_conf(mvchip));
++ mvchip->blink_en_reg = readl(mvebu_gpioreg_blink(mvchip));
++ mvchip->in_pol_reg = readl(mvebu_gpioreg_in_pol(mvchip));
++
++ switch (mvchip->soc_variant) {
++ case MVEBU_GPIO_SOC_VARIANT_ORION:
++ mvchip->edge_mask_regs[0] =
++ readl(mvchip->membase + GPIO_EDGE_MASK_OFF);
++ mvchip->level_mask_regs[0] =
++ readl(mvchip->membase + GPIO_LEVEL_MASK_OFF);
++ break;
++ case MVEBU_GPIO_SOC_VARIANT_MV78200:
++ for (i = 0; i < 2; i++) {
++ mvchip->edge_mask_regs[i] =
++ readl(mvchip->membase +
++ GPIO_EDGE_MASK_MV78200_OFF(i));
++ mvchip->level_mask_regs[i] =
++ readl(mvchip->membase +
++ GPIO_LEVEL_MASK_MV78200_OFF(i));
++ }
++ break;
++ case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
++ for (i = 0; i < 4; i++) {
++ mvchip->edge_mask_regs[i] =
++ readl(mvchip->membase +
++ GPIO_EDGE_MASK_ARMADAXP_OFF(i));
++ mvchip->level_mask_regs[i] =
++ readl(mvchip->membase +
++ GPIO_LEVEL_MASK_ARMADAXP_OFF(i));
++ }
++ break;
++ default:
++ BUG();
++ }
++
++ return 0;
++}
++
++static int mvebu_gpio_resume(struct platform_device *pdev)
++{
++ struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev);
++ int i;
++
++ writel(mvchip->out_reg, mvebu_gpioreg_out(mvchip));
++ writel(mvchip->io_conf_reg, mvebu_gpioreg_io_conf(mvchip));
++ writel(mvchip->blink_en_reg, mvebu_gpioreg_blink(mvchip));
++ writel(mvchip->in_pol_reg, mvebu_gpioreg_in_pol(mvchip));
++
++ switch (mvchip->soc_variant) {
++ case MVEBU_GPIO_SOC_VARIANT_ORION:
++ writel(mvchip->edge_mask_regs[0],
++ mvchip->membase + GPIO_EDGE_MASK_OFF);
++ writel(mvchip->level_mask_regs[0],
++ mvchip->membase + GPIO_LEVEL_MASK_OFF);
++ break;
++ case MVEBU_GPIO_SOC_VARIANT_MV78200:
++ for (i = 0; i < 2; i++) {
++ writel(mvchip->edge_mask_regs[i],
++ mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(i));
++ writel(mvchip->level_mask_regs[i],
++ mvchip->membase +
++ GPIO_LEVEL_MASK_MV78200_OFF(i));
++ }
++ break;
++ case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
++ for (i = 0; i < 4; i++) {
++ writel(mvchip->edge_mask_regs[i],
++ mvchip->membase +
++ GPIO_EDGE_MASK_ARMADAXP_OFF(i));
++ writel(mvchip->level_mask_regs[i],
++ mvchip->membase +
++ GPIO_LEVEL_MASK_ARMADAXP_OFF(i));
++ }
++ break;
++ default:
++ BUG();
++ }
++
++ return 0;
++}
++
+ static int mvebu_gpio_probe(struct platform_device *pdev)
+ {
+ struct mvebu_gpio_chip *mvchip;
+@@ -585,6 +680,8 @@ static int mvebu_gpio_probe(struct platf
+ if (!mvchip)
+ return -ENOMEM;
+
++ platform_set_drvdata(pdev, mvchip);
++
+ if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) {
+ dev_err(&pdev->dev, "Missing ngpios OF property\n");
+ return -ENODEV;
+@@ -743,5 +840,7 @@ static struct platform_driver mvebu_gpio
+ .of_match_table = mvebu_gpio_of_match,
+ },
+ .probe = mvebu_gpio_probe,
++ .suspend = mvebu_gpio_suspend,
++ .resume = mvebu_gpio_resume,
+ };
+ module_platform_driver(mvebu_gpio_driver);