linux/drivers/cpuidle/cpuidle-mvebu-v7.c
<<
>>
Prefs
   1/*
   2 * Marvell Armada 370, 38x and XP SoC cpuidle driver
   3 *
   4 * Copyright (C) 2014 Marvell
   5 *
   6 * Nadav Haklai <nadavh@marvell.com>
   7 * Gregory CLEMENT <gregory.clement@free-electrons.com>
   8 *
   9 * This file is licensed under the terms of the GNU General Public
  10 * License version 2.  This program is licensed "as is" without any
  11 * warranty of any kind, whether express or implied.
  12 *
  13 * Maintainer: Gregory CLEMENT <gregory.clement@free-electrons.com>
  14 */
  15
  16#include <linux/cpu_pm.h>
  17#include <linux/cpuidle.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/suspend.h>
  21#include <linux/platform_device.h>
  22#include <asm/cpuidle.h>
  23
  24#define MVEBU_V7_FLAG_DEEP_IDLE 0x10000
  25
  26static int (*mvebu_v7_cpu_suspend)(int);
  27
  28static int mvebu_v7_enter_idle(struct cpuidle_device *dev,
  29                                struct cpuidle_driver *drv,
  30                                int index)
  31{
  32        int ret;
  33        bool deepidle = false;
  34        cpu_pm_enter();
  35
  36        if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE)
  37                deepidle = true;
  38
  39        ret = mvebu_v7_cpu_suspend(deepidle);
  40        cpu_pm_exit();
  41
  42        if (ret)
  43                return ret;
  44
  45        return index;
  46}
  47
  48static struct cpuidle_driver armadaxp_idle_driver = {
  49        .name                   = "armada_xp_idle",
  50        .states[0]              = ARM_CPUIDLE_WFI_STATE,
  51        .states[1]              = {
  52                .enter                  = mvebu_v7_enter_idle,
  53                .exit_latency           = 100,
  54                .power_usage            = 50,
  55                .target_residency       = 1000,
  56                .name                   = "MV CPU IDLE",
  57                .desc                   = "CPU power down",
  58        },
  59        .states[2]              = {
  60                .enter                  = mvebu_v7_enter_idle,
  61                .exit_latency           = 1000,
  62                .power_usage            = 5,
  63                .target_residency       = 10000,
  64                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
  65                .name                   = "MV CPU DEEP IDLE",
  66                .desc                   = "CPU and L2 Fabric power down",
  67        },
  68        .state_count = 3,
  69};
  70
  71static struct cpuidle_driver armada370_idle_driver = {
  72        .name                   = "armada_370_idle",
  73        .states[0]              = ARM_CPUIDLE_WFI_STATE,
  74        .states[1]              = {
  75                .enter                  = mvebu_v7_enter_idle,
  76                .exit_latency           = 100,
  77                .power_usage            = 5,
  78                .target_residency       = 1000,
  79                .flags                  = MVEBU_V7_FLAG_DEEP_IDLE,
  80                .name                   = "Deep Idle",
  81                .desc                   = "CPU and L2 Fabric power down",
  82        },
  83        .state_count = 2,
  84};
  85
  86static struct cpuidle_driver armada38x_idle_driver = {
  87        .name                   = "armada_38x_idle",
  88        .states[0]              = ARM_CPUIDLE_WFI_STATE,
  89        .states[1]              = {
  90                .enter                  = mvebu_v7_enter_idle,
  91                .exit_latency           = 10,
  92                .power_usage            = 5,
  93                .target_residency       = 100,
  94                .name                   = "Idle",
  95                .desc                   = "CPU and SCU power down",
  96        },
  97        .state_count = 2,
  98};
  99
 100static int mvebu_v7_cpuidle_probe(struct platform_device *pdev)
 101{
 102        const struct platform_device_id *id = pdev->id_entry;
 103
 104        if (!id)
 105                return -EINVAL;
 106
 107        mvebu_v7_cpu_suspend = pdev->dev.platform_data;
 108
 109        return cpuidle_register((struct cpuidle_driver *)id->driver_data, NULL);
 110}
 111
 112static const struct platform_device_id mvebu_cpuidle_ids[] = {
 113        {
 114                .name = "cpuidle-armada-xp",
 115                .driver_data = (unsigned long)&armadaxp_idle_driver,
 116        }, {
 117                .name = "cpuidle-armada-370",
 118                .driver_data = (unsigned long)&armada370_idle_driver,
 119        }, {
 120                .name = "cpuidle-armada-38x",
 121                .driver_data = (unsigned long)&armada38x_idle_driver,
 122        },
 123        {}
 124};
 125
 126static struct platform_driver mvebu_cpuidle_driver = {
 127        .probe = mvebu_v7_cpuidle_probe,
 128        .driver = {
 129                .name = "cpuidle-mbevu",
 130                .suppress_bind_attrs = true,
 131        },
 132        .id_table = mvebu_cpuidle_ids,
 133};
 134
 135builtin_platform_driver(mvebu_cpuidle_driver);
 136
 137MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
 138MODULE_DESCRIPTION("Marvell EBU v7 cpuidle driver");
 139MODULE_LICENSE("GPL");
 140