linux/arch/arm/mach-mvebu/pm-board.c
<<
>>
Prefs
   1/*
   2 * Board-level suspend/resume support.
   3 *
   4 * Copyright (C) 2014-2015 Marvell
   5 *
   6 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
   7 *
   8 * This file is licensed under the terms of the GNU General Public
   9 * License version 2.  This program is licensed "as is" without any
  10 * warranty of any kind, whether express or implied.
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/gpio.h>
  15#include <linux/init.h>
  16#include <linux/io.h>
  17#include <linux/of.h>
  18#include <linux/of_address.h>
  19#include <linux/of_gpio.h>
  20#include <linux/slab.h>
  21#include "common.h"
  22
  23#define ARMADA_PIC_NR_GPIOS 3
  24
  25static void __iomem *gpio_ctrl;
  26static int pic_gpios[ARMADA_PIC_NR_GPIOS];
  27static int pic_raw_gpios[ARMADA_PIC_NR_GPIOS];
  28
  29static void mvebu_armada_pm_enter(void __iomem *sdram_reg, u32 srcmd)
  30{
  31        u32 reg, ackcmd;
  32        int i;
  33
  34        /* Put 001 as value on the GPIOs */
  35        reg = readl(gpio_ctrl);
  36        for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++)
  37                reg &= ~BIT(pic_raw_gpios[i]);
  38        reg |= BIT(pic_raw_gpios[0]);
  39        writel(reg, gpio_ctrl);
  40
  41        /* Prepare writing 111 to the GPIOs */
  42        ackcmd = readl(gpio_ctrl);
  43        for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++)
  44                ackcmd |= BIT(pic_raw_gpios[i]);
  45
  46        srcmd = cpu_to_le32(srcmd);
  47        ackcmd = cpu_to_le32(ackcmd);
  48
  49        /*
  50         * Wait a while, the PIC needs quite a bit of time between the
  51         * two GPIO commands.
  52         */
  53        mdelay(3000);
  54
  55        asm volatile (
  56                /* Align to a cache line */
  57                ".balign 32\n\t"
  58
  59                /* Enter self refresh */
  60                "str %[srcmd], [%[sdram_reg]]\n\t"
  61
  62                /*
  63                 * Wait 100 cycles for DDR to enter self refresh, by
  64                 * doing 50 times two instructions.
  65                 */
  66                "mov r1, #50\n\t"
  67                "1: subs r1, r1, #1\n\t"
  68                "bne 1b\n\t"
  69
  70                /* Issue the command ACK */
  71                "str %[ackcmd], [%[gpio_ctrl]]\n\t"
  72
  73                /* Trap the processor */
  74                "b .\n\t"
  75                : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
  76                  [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1");
  77}
  78
  79static int __init mvebu_armada_pm_init(void)
  80{
  81        struct device_node *np;
  82        struct device_node *gpio_ctrl_np = NULL;
  83        int ret = 0, i;
  84
  85        if (!of_machine_is_compatible("marvell,axp-gp"))
  86                return -ENODEV;
  87
  88        np = of_find_node_by_name(NULL, "pm_pic");
  89        if (!np)
  90                return -ENODEV;
  91
  92        for (i = 0; i < ARMADA_PIC_NR_GPIOS; i++) {
  93                char *name;
  94                struct of_phandle_args args;
  95
  96                pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i);
  97                if (pic_gpios[i] < 0) {
  98                        ret = -ENODEV;
  99                        goto out;
 100                }
 101
 102                name = kasprintf(GFP_KERNEL, "pic-pin%d", i);
 103                if (!name) {
 104                        ret = -ENOMEM;
 105                        goto out;
 106                }
 107
 108                ret = gpio_request(pic_gpios[i], name);
 109                if (ret < 0) {
 110                        kfree(name);
 111                        goto out;
 112                }
 113
 114                ret = gpio_direction_output(pic_gpios[i], 0);
 115                if (ret < 0) {
 116                        gpio_free(pic_gpios[i]);
 117                        kfree(name);
 118                        goto out;
 119                }
 120
 121                ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2,
 122                                                       i, &args);
 123                if (ret < 0) {
 124                        gpio_free(pic_gpios[i]);
 125                        kfree(name);
 126                        goto out;
 127                }
 128
 129                if (gpio_ctrl_np)
 130                        of_node_put(gpio_ctrl_np);
 131                gpio_ctrl_np = args.np;
 132                pic_raw_gpios[i] = args.args[0];
 133        }
 134
 135        gpio_ctrl = of_iomap(gpio_ctrl_np, 0);
 136        if (!gpio_ctrl) {
 137                ret = -ENOMEM;
 138                goto out;
 139        }
 140
 141        mvebu_pm_suspend_init(mvebu_armada_pm_enter);
 142
 143out:
 144        of_node_put(np);
 145        of_node_put(gpio_ctrl_np);
 146        return ret;
 147}
 148
 149/*
 150 * Registering the mvebu_board_pm_enter callback must be done before
 151 * the platform_suspend_ops will be registered. In the same time we
 152 * also need to have the gpio devices registered. That's why we use a
 153 * device_initcall_sync which is called after all the device_initcall
 154 * (used by the gpio device) but before the late_initcall (used to
 155 * register the platform_suspend_ops)
 156 */
 157device_initcall_sync(mvebu_armada_pm_init);
 158