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