Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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