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
  78static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
  79{
  80        /* print power state count */
  81        seq_printf(s, "ux500-regulator power state count: %i\n",
  82                   power_state_active_get());
  83
  84        return 0;
  85}
  86
  87static int ux500_regulator_power_state_cnt_open(struct inode *inode,
  88        struct file *file)
  89{
  90        return single_open(file, ux500_regulator_power_state_cnt_print,
  91                inode->i_private);
  92}
  93
  94static const struct file_operations ux500_regulator_power_state_cnt_fops = {
  95        .open = ux500_regulator_power_state_cnt_open,
  96        .read = seq_read,
  97        .llseek = seq_lseek,
  98        .release = single_release,
  99        .owner = THIS_MODULE,
 100};
 101
 102static int ux500_regulator_status_print(struct seq_file *s, void *p)
 103{
 104        int i;
 105
 106        /* print dump header */
 107        seq_puts(s, "ux500-regulator status:\n");
 108        seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after");
 109
 110        for (i = 0; i < rdebug.num_regulators; i++) {
 111                struct dbx500_regulator_info *info;
 112                /* Access per-regulator data */
 113                info = &rdebug.regulator_array[i];
 114
 115                /* print status */
 116                seq_printf(s, "%20s : %8s : %8s : %8s\n",
 117                           info->desc.name,
 118                           info->is_enabled ? "enabled" : "disabled",
 119                           rdebug.state_before_suspend[i] ? "enabled" : "disabled",
 120                           rdebug.state_after_suspend[i] ? "enabled" : "disabled");
 121        }
 122
 123        return 0;
 124}
 125
 126static int ux500_regulator_status_open(struct inode *inode, struct file *file)
 127{
 128        return single_open(file, ux500_regulator_status_print,
 129                inode->i_private);
 130}
 131
 132static const struct file_operations ux500_regulator_status_fops = {
 133        .open = ux500_regulator_status_open,
 134        .read = seq_read,
 135        .llseek = seq_lseek,
 136        .release = single_release,
 137        .owner = THIS_MODULE,
 138};
 139
 140int __attribute__((weak)) dbx500_regulator_testcase(
 141        struct dbx500_regulator_info *regulator_info,
 142        int num_regulators)
 143{
 144        return 0;
 145}
 146
 147int
 148ux500_regulator_debug_init(struct platform_device *pdev,
 149        struct dbx500_regulator_info *regulator_info,
 150        int num_regulators)
 151{
 152        /* create directory */
 153        rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
 154        if (!rdebug.dir)
 155                goto exit_no_debugfs;
 156
 157        /* create "status" file */
 158        rdebug.status_file = debugfs_create_file("status",
 159                S_IRUGO, rdebug.dir, &pdev->dev,
 160                &ux500_regulator_status_fops);
 161        if (!rdebug.status_file)
 162                goto exit_destroy_dir;
 163
 164        /* create "power-state-count" file */
 165        rdebug.power_state_cnt_file = debugfs_create_file("power-state-count",
 166                S_IRUGO, rdebug.dir, &pdev->dev,
 167                &ux500_regulator_power_state_cnt_fops);
 168        if (!rdebug.power_state_cnt_file)
 169                goto exit_destroy_status;
 170
 171        rdebug.regulator_array = regulator_info;
 172        rdebug.num_regulators = num_regulators;
 173
 174        rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
 175        if (!rdebug.state_before_suspend)
 176                goto exit_destroy_power_state;
 177
 178        rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
 179        if (!rdebug.state_after_suspend)
 180                goto exit_free;
 181
 182        dbx500_regulator_testcase(regulator_info, num_regulators);
 183        return 0;
 184
 185exit_free:
 186        kfree(rdebug.state_before_suspend);
 187exit_destroy_power_state:
 188        debugfs_remove(rdebug.power_state_cnt_file);
 189exit_destroy_status:
 190        debugfs_remove(rdebug.status_file);
 191exit_destroy_dir:
 192        debugfs_remove(rdebug.dir);
 193exit_no_debugfs:
 194        dev_err(&pdev->dev, "failed to create debugfs entries.\n");
 195        return -ENOMEM;
 196}
 197
 198int ux500_regulator_debug_exit(void)
 199{
 200        debugfs_remove_recursive(rdebug.dir);
 201        kfree(rdebug.state_after_suspend);
 202        kfree(rdebug.state_before_suspend);
 203
 204        return 0;
 205}
 206#endif
 207