linux/drivers/regulator/dbx500-prcmu.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) ST-Ericsson SA 2010
   3 *
   4 * License Terms: GNU General Public License v2
   5 * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
   6 *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
   7 *
   8 * UX500 common part of Power domain regulators
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/err.h>
  13#include <linux/regulator/driver.h>
  14#include <linux/debugfs.h>
  15#include <linux/seq_file.h>
  16#include <linux/slab.h>
  17#include <linux/module.h>
  18
  19#include "dbx500-prcmu.h"
  20
  21/*
  22 * power state reference count
  23 */
  24static int power_state_active_cnt; /* will initialize to zero */
  25static DEFINE_SPINLOCK(power_state_active_lock);
  26
  27void power_state_active_enable(void)
  28{
  29        unsigned long flags;
  30
  31        spin_lock_irqsave(&power_state_active_lock, flags);
  32        power_state_active_cnt++;
  33        spin_unlock_irqrestore(&power_state_active_lock, flags);
  34}
  35
  36int power_state_active_disable(void)
  37{
  38        int ret = 0;
  39        unsigned long flags;
  40
  41        spin_lock_irqsave(&power_state_active_lock, flags);
  42        if (power_state_active_cnt <= 0) {
  43                pr_err("power state: unbalanced enable/disable calls\n");
  44                ret = -EINVAL;
  45                goto out;
  46        }
  47
  48        power_state_active_cnt--;
  49out:
  50        spin_unlock_irqrestore(&power_state_active_lock, flags);
  51        return ret;
  52}
  53
  54#ifdef CONFIG_REGULATOR_DEBUG
  55
  56static int power_state_active_get(void)
  57{
  58        unsigned long flags;
  59        int cnt;
  60
  61        spin_lock_irqsave(&power_state_active_lock, flags);
  62        cnt = power_state_active_cnt;
  63        spin_unlock_irqrestore(&power_state_active_lock, flags);
  64
  65        return cnt;
  66}
  67
  68static struct ux500_regulator_debug {
  69        struct dentry *dir;
  70        struct dentry *status_file;
  71        struct dentry *power_state_cnt_file;
  72        struct dbx500_regulator_info *regulator_array;
  73        int num_regulators;
  74        u8 *state_before_suspend;
  75        u8 *state_after_suspend;
  76} rdebug;
  77
  78void ux500_regulator_suspend_debug(void)
  79{
  80        int i;
  81        for (i = 0; i < rdebug.num_regulators; i++)
  82                rdebug.state_before_suspend[i] =
  83                        rdebug.regulator_array[i].is_enabled;
  84}
  85
  86void ux500_regulator_resume_debug(void)
  87{
  88        int i;
  89        for (i = 0; i < rdebug.num_regulators; i++)
  90                rdebug.state_after_suspend[i] =
  91                        rdebug.regulator_array[i].is_enabled;
  92}
  93
  94static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
  95{
  96        struct device *dev = s->private;
  97        int err;
  98
  99        /* print power state count */
 100        err = seq_printf(s, "ux500-regulator power state count: %i\n",
 101                power_state_active_get());
 102        if (err < 0)
 103                dev_err(dev, "seq_printf overflow\n");
 104
 105        return 0;
 106}
 107
 108static int ux500_regulator_power_state_cnt_open(struct inode *inode,
 109        struct file *file)
 110{
 111        return single_open(file, ux500_regulator_power_state_cnt_print,
 112                inode->i_private);
 113}
 114
 115static const struct file_operations ux500_regulator_power_state_cnt_fops = {
 116        .open = ux500_regulator_power_state_cnt_open,
 117        .read = seq_read,
 118        .llseek = seq_lseek,
 119        .release = single_release,
 120        .owner = THIS_MODULE,
 121};
 122
 123static int ux500_regulator_status_print(struct seq_file *s, void *p)
 124{
 125        struct device *dev = s->private;
 126        int err;
 127        int i;
 128
 129        /* print dump header */
 130        err = seq_printf(s, "ux500-regulator status:\n");
 131        if (err < 0)
 132                dev_err(dev, "seq_printf overflow\n");
 133
 134        err = seq_printf(s, "%31s : %8s : %8s\n", "current",
 135                "before", "after");
 136        if (err < 0)
 137                dev_err(dev, "seq_printf overflow\n");
 138
 139        for (i = 0; i < rdebug.num_regulators; i++) {
 140                struct dbx500_regulator_info *info;
 141                /* Access per-regulator data */
 142                info = &rdebug.regulator_array[i];
 143
 144                /* print status */
 145                err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name,
 146                        info->is_enabled ? "enabled" : "disabled",
 147                        rdebug.state_before_suspend[i] ? "enabled" : "disabled",
 148                        rdebug.state_after_suspend[i] ? "enabled" : "disabled");
 149                if (err < 0)
 150                        dev_err(dev, "seq_printf overflow\n");
 151        }
 152
 153        return 0;
 154}
 155
 156static int ux500_regulator_status_open(struct inode *inode, struct file *file)
 157{
 158        return single_open(file, ux500_regulator_status_print,
 159                inode->i_private);
 160}
 161
 162static const struct file_operations ux500_regulator_status_fops = {
 163        .open = ux500_regulator_status_open,
 164        .read = seq_read,
 165        .llseek = seq_lseek,
 166        .release = single_release,
 167        .owner = THIS_MODULE,
 168};
 169
 170int __attribute__((weak)) dbx500_regulator_testcase(
 171        struct dbx500_regulator_info *regulator_info,
 172        int num_regulators)
 173{
 174        return 0;
 175}
 176
 177int
 178ux500_regulator_debug_init(struct platform_device *pdev,
 179        struct dbx500_regulator_info *regulator_info,
 180        int num_regulators)
 181{
 182        /* create directory */
 183        rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
 184        if (!rdebug.dir)
 185                goto exit_no_debugfs;
 186
 187        /* create "status" file */
 188        rdebug.status_file = debugfs_create_file("status",
 189                S_IRUGO, rdebug.dir, &pdev->dev,
 190                &ux500_regulator_status_fops);
 191        if (!rdebug.status_file)
 192                goto exit_destroy_dir;
 193
 194        /* create "power-state-count" file */
 195        rdebug.power_state_cnt_file = debugfs_create_file("power-state-count",
 196                S_IRUGO, rdebug.dir, &pdev->dev,
 197                &ux500_regulator_power_state_cnt_fops);
 198        if (!rdebug.power_state_cnt_file)
 199                goto exit_destroy_status;
 200
 201        rdebug.regulator_array = regulator_info;
 202        rdebug.num_regulators = num_regulators;
 203
 204        rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
 205        if (!rdebug.state_before_suspend) {
 206                dev_err(&pdev->dev,
 207                        "could not allocate memory for saving state\n");
 208                goto exit_destroy_power_state;
 209        }
 210
 211        rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
 212        if (!rdebug.state_after_suspend) {
 213                dev_err(&pdev->dev,
 214                        "could not allocate memory for saving state\n");
 215                goto exit_free;
 216        }
 217
 218        dbx500_regulator_testcase(regulator_info, num_regulators);
 219        return 0;
 220
 221exit_free:
 222        kfree(rdebug.state_before_suspend);
 223exit_destroy_power_state:
 224        debugfs_remove(rdebug.power_state_cnt_file);
 225exit_destroy_status:
 226        debugfs_remove(rdebug.status_file);
 227exit_destroy_dir:
 228        debugfs_remove(rdebug.dir);
 229exit_no_debugfs:
 230        dev_err(&pdev->dev, "failed to create debugfs entries.\n");
 231        return -ENOMEM;
 232}
 233
 234int ux500_regulator_debug_exit(void)
 235{
 236        debugfs_remove_recursive(rdebug.dir);
 237        kfree(rdebug.state_after_suspend);
 238        kfree(rdebug.state_before_suspend);
 239
 240        return 0;
 241}
 242#endif
 243