linux/drivers/regulator/dbx500-prcmu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) ST-Ericsson SA 2010
   4 *
   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 dbx500_regulator_info *regulator_array;
  71        int num_regulators;
  72        u8 *state_before_suspend;
  73        u8 *state_after_suspend;
  74} rdebug;
  75
  76static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p)
  77{
  78        /* print power state count */
  79        seq_printf(s, "ux500-regulator power state count: %i\n",
  80                   power_state_active_get());
  81
  82        return 0;
  83}
  84DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt);
  85
  86static int ux500_regulator_status_show(struct seq_file *s, void *p)
  87{
  88        int i;
  89
  90        /* print dump header */
  91        seq_puts(s, "ux500-regulator status:\n");
  92        seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after");
  93
  94        for (i = 0; i < rdebug.num_regulators; i++) {
  95                struct dbx500_regulator_info *info;
  96                /* Access per-regulator data */
  97                info = &rdebug.regulator_array[i];
  98
  99                /* print status */
 100                seq_printf(s, "%20s : %8s : %8s : %8s\n",
 101                           info->desc.name,
 102                           info->is_enabled ? "enabled" : "disabled",
 103                           rdebug.state_before_suspend[i] ? "enabled" : "disabled",
 104                           rdebug.state_after_suspend[i] ? "enabled" : "disabled");
 105        }
 106
 107        return 0;
 108}
 109DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status);
 110
 111int
 112ux500_regulator_debug_init(struct platform_device *pdev,
 113        struct dbx500_regulator_info *regulator_info,
 114        int num_regulators)
 115{
 116        /* create directory */
 117        rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
 118
 119        /* create "status" file */
 120        debugfs_create_file("status", 0444, rdebug.dir, &pdev->dev,
 121                            &ux500_regulator_status_fops);
 122
 123        /* create "power-state-count" file */
 124        debugfs_create_file("power-state-count", 0444, rdebug.dir,
 125                            &pdev->dev, &ux500_regulator_power_state_cnt_fops);
 126
 127        rdebug.regulator_array = regulator_info;
 128        rdebug.num_regulators = num_regulators;
 129
 130        rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
 131        if (!rdebug.state_before_suspend)
 132                goto exit_destroy_power_state;
 133
 134        rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
 135        if (!rdebug.state_after_suspend)
 136                goto exit_free;
 137
 138        return 0;
 139
 140exit_free:
 141        kfree(rdebug.state_before_suspend);
 142exit_destroy_power_state:
 143        debugfs_remove_recursive(rdebug.dir);
 144        return -ENOMEM;
 145}
 146
 147int ux500_regulator_debug_exit(void)
 148{
 149        debugfs_remove_recursive(rdebug.dir);
 150        kfree(rdebug.state_after_suspend);
 151        kfree(rdebug.state_before_suspend);
 152
 153        return 0;
 154}
 155#endif
 156