138e96838SBengt Jonsson /*
238e96838SBengt Jonsson  * Copyright (C) ST-Ericsson SA 2010
338e96838SBengt Jonsson  *
438e96838SBengt Jonsson  * License Terms: GNU General Public License v2
538e96838SBengt Jonsson  * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
638e96838SBengt Jonsson  *          Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
738e96838SBengt Jonsson  *
838e96838SBengt Jonsson  * UX500 common part of Power domain regulators
938e96838SBengt Jonsson  */
1038e96838SBengt Jonsson 
1138e96838SBengt Jonsson #include <linux/kernel.h>
1238e96838SBengt Jonsson #include <linux/err.h>
1338e96838SBengt Jonsson #include <linux/regulator/driver.h>
1438e96838SBengt Jonsson #include <linux/debugfs.h>
1538e96838SBengt Jonsson #include <linux/seq_file.h>
1638e96838SBengt Jonsson #include <linux/slab.h>
177f46d0f8SSteven Rostedt #include <linux/module.h>
1838e96838SBengt Jonsson 
1938e96838SBengt Jonsson #include "dbx500-prcmu.h"
2038e96838SBengt Jonsson 
2138e96838SBengt Jonsson /*
2238e96838SBengt Jonsson  * power state reference count
2338e96838SBengt Jonsson  */
2438e96838SBengt Jonsson static int power_state_active_cnt; /* will initialize to zero */
2538e96838SBengt Jonsson static DEFINE_SPINLOCK(power_state_active_lock);
2638e96838SBengt Jonsson 
2738e96838SBengt Jonsson void power_state_active_enable(void)
2838e96838SBengt Jonsson {
2938e96838SBengt Jonsson 	unsigned long flags;
3038e96838SBengt Jonsson 
3138e96838SBengt Jonsson 	spin_lock_irqsave(&power_state_active_lock, flags);
3238e96838SBengt Jonsson 	power_state_active_cnt++;
3338e96838SBengt Jonsson 	spin_unlock_irqrestore(&power_state_active_lock, flags);
3438e96838SBengt Jonsson }
3538e96838SBengt Jonsson 
3638e96838SBengt Jonsson int power_state_active_disable(void)
3738e96838SBengt Jonsson {
3838e96838SBengt Jonsson 	int ret = 0;
3938e96838SBengt Jonsson 	unsigned long flags;
4038e96838SBengt Jonsson 
4138e96838SBengt Jonsson 	spin_lock_irqsave(&power_state_active_lock, flags);
4238e96838SBengt Jonsson 	if (power_state_active_cnt <= 0) {
4338e96838SBengt Jonsson 		pr_err("power state: unbalanced enable/disable calls\n");
4438e96838SBengt Jonsson 		ret = -EINVAL;
4538e96838SBengt Jonsson 		goto out;
4638e96838SBengt Jonsson 	}
4738e96838SBengt Jonsson 
4838e96838SBengt Jonsson 	power_state_active_cnt--;
4938e96838SBengt Jonsson out:
5038e96838SBengt Jonsson 	spin_unlock_irqrestore(&power_state_active_lock, flags);
5138e96838SBengt Jonsson 	return ret;
5238e96838SBengt Jonsson }
5338e96838SBengt Jonsson 
5438e96838SBengt Jonsson #ifdef CONFIG_REGULATOR_DEBUG
5538e96838SBengt Jonsson 
563d75095aSSachin Kamat static int power_state_active_get(void)
573d75095aSSachin Kamat {
583d75095aSSachin Kamat 	unsigned long flags;
593d75095aSSachin Kamat 	int cnt;
603d75095aSSachin Kamat 
613d75095aSSachin Kamat 	spin_lock_irqsave(&power_state_active_lock, flags);
623d75095aSSachin Kamat 	cnt = power_state_active_cnt;
633d75095aSSachin Kamat 	spin_unlock_irqrestore(&power_state_active_lock, flags);
643d75095aSSachin Kamat 
653d75095aSSachin Kamat 	return cnt;
663d75095aSSachin Kamat }
673d75095aSSachin Kamat 
6838e96838SBengt Jonsson static struct ux500_regulator_debug {
6938e96838SBengt Jonsson 	struct dentry *dir;
7038e96838SBengt Jonsson 	struct dentry *status_file;
7138e96838SBengt Jonsson 	struct dentry *power_state_cnt_file;
7238e96838SBengt Jonsson 	struct dbx500_regulator_info *regulator_array;
7338e96838SBengt Jonsson 	int num_regulators;
7438e96838SBengt Jonsson 	u8 *state_before_suspend;
7538e96838SBengt Jonsson 	u8 *state_after_suspend;
7638e96838SBengt Jonsson } rdebug;
7738e96838SBengt Jonsson 
7838e96838SBengt Jonsson void ux500_regulator_suspend_debug(void)
7938e96838SBengt Jonsson {
8038e96838SBengt Jonsson 	int i;
8138e96838SBengt Jonsson 	for (i = 0; i < rdebug.num_regulators; i++)
8238e96838SBengt Jonsson 		rdebug.state_before_suspend[i] =
8338e96838SBengt Jonsson 			rdebug.regulator_array[i].is_enabled;
8438e96838SBengt Jonsson }
8538e96838SBengt Jonsson 
8638e96838SBengt Jonsson void ux500_regulator_resume_debug(void)
8738e96838SBengt Jonsson {
8838e96838SBengt Jonsson 	int i;
8938e96838SBengt Jonsson 	for (i = 0; i < rdebug.num_regulators; i++)
9038e96838SBengt Jonsson 		rdebug.state_after_suspend[i] =
9138e96838SBengt Jonsson 			rdebug.regulator_array[i].is_enabled;
9238e96838SBengt Jonsson }
9338e96838SBengt Jonsson 
9438e96838SBengt Jonsson static int ux500_regulator_power_state_cnt_print(struct seq_file *s, void *p)
9538e96838SBengt Jonsson {
9638e96838SBengt Jonsson 	struct device *dev = s->private;
9738e96838SBengt Jonsson 	int err;
9838e96838SBengt Jonsson 
9938e96838SBengt Jonsson 	/* print power state count */
10038e96838SBengt Jonsson 	err = seq_printf(s, "ux500-regulator power state count: %i\n",
10138e96838SBengt Jonsson 		power_state_active_get());
10238e96838SBengt Jonsson 	if (err < 0)
10338e96838SBengt Jonsson 		dev_err(dev, "seq_printf overflow\n");
10438e96838SBengt Jonsson 
10538e96838SBengt Jonsson 	return 0;
10638e96838SBengt Jonsson }
10738e96838SBengt Jonsson 
10838e96838SBengt Jonsson static int ux500_regulator_power_state_cnt_open(struct inode *inode,
10938e96838SBengt Jonsson 	struct file *file)
11038e96838SBengt Jonsson {
11138e96838SBengt Jonsson 	return single_open(file, ux500_regulator_power_state_cnt_print,
11238e96838SBengt Jonsson 		inode->i_private);
11338e96838SBengt Jonsson }
11438e96838SBengt Jonsson 
11538e96838SBengt Jonsson static const struct file_operations ux500_regulator_power_state_cnt_fops = {
11638e96838SBengt Jonsson 	.open = ux500_regulator_power_state_cnt_open,
11738e96838SBengt Jonsson 	.read = seq_read,
11838e96838SBengt Jonsson 	.llseek = seq_lseek,
11938e96838SBengt Jonsson 	.release = single_release,
12038e96838SBengt Jonsson 	.owner = THIS_MODULE,
12138e96838SBengt Jonsson };
12238e96838SBengt Jonsson 
12338e96838SBengt Jonsson static int ux500_regulator_status_print(struct seq_file *s, void *p)
12438e96838SBengt Jonsson {
12538e96838SBengt Jonsson 	struct device *dev = s->private;
12638e96838SBengt Jonsson 	int err;
12738e96838SBengt Jonsson 	int i;
12838e96838SBengt Jonsson 
12938e96838SBengt Jonsson 	/* print dump header */
13038e96838SBengt Jonsson 	err = seq_printf(s, "ux500-regulator status:\n");
13138e96838SBengt Jonsson 	if (err < 0)
13238e96838SBengt Jonsson 		dev_err(dev, "seq_printf overflow\n");
13338e96838SBengt Jonsson 
13438e96838SBengt Jonsson 	err = seq_printf(s, "%31s : %8s : %8s\n", "current",
13538e96838SBengt Jonsson 		"before", "after");
13638e96838SBengt Jonsson 	if (err < 0)
13738e96838SBengt Jonsson 		dev_err(dev, "seq_printf overflow\n");
13838e96838SBengt Jonsson 
13938e96838SBengt Jonsson 	for (i = 0; i < rdebug.num_regulators; i++) {
14038e96838SBengt Jonsson 		struct dbx500_regulator_info *info;
14138e96838SBengt Jonsson 		/* Access per-regulator data */
14238e96838SBengt Jonsson 		info = &rdebug.regulator_array[i];
14338e96838SBengt Jonsson 
14438e96838SBengt Jonsson 		/* print status */
14538e96838SBengt Jonsson 		err = seq_printf(s, "%20s : %8s : %8s : %8s\n", info->desc.name,
14638e96838SBengt Jonsson 			info->is_enabled ? "enabled" : "disabled",
14738e96838SBengt Jonsson 			rdebug.state_before_suspend[i] ? "enabled" : "disabled",
14838e96838SBengt Jonsson 			rdebug.state_after_suspend[i] ? "enabled" : "disabled");
14938e96838SBengt Jonsson 		if (err < 0)
15038e96838SBengt Jonsson 			dev_err(dev, "seq_printf overflow\n");
15138e96838SBengt Jonsson 	}
15238e96838SBengt Jonsson 
15338e96838SBengt Jonsson 	return 0;
15438e96838SBengt Jonsson }
15538e96838SBengt Jonsson 
15638e96838SBengt Jonsson static int ux500_regulator_status_open(struct inode *inode, struct file *file)
15738e96838SBengt Jonsson {
15838e96838SBengt Jonsson 	return single_open(file, ux500_regulator_status_print,
15938e96838SBengt Jonsson 		inode->i_private);
16038e96838SBengt Jonsson }
16138e96838SBengt Jonsson 
16238e96838SBengt Jonsson static const struct file_operations ux500_regulator_status_fops = {
16338e96838SBengt Jonsson 	.open = ux500_regulator_status_open,
16438e96838SBengt Jonsson 	.read = seq_read,
16538e96838SBengt Jonsson 	.llseek = seq_lseek,
16638e96838SBengt Jonsson 	.release = single_release,
16738e96838SBengt Jonsson 	.owner = THIS_MODULE,
16838e96838SBengt Jonsson };
16938e96838SBengt Jonsson 
17038e96838SBengt Jonsson int __attribute__((weak)) dbx500_regulator_testcase(
17138e96838SBengt Jonsson 	struct dbx500_regulator_info *regulator_info,
17238e96838SBengt Jonsson 	int num_regulators)
17338e96838SBengt Jonsson {
17438e96838SBengt Jonsson 	return 0;
17538e96838SBengt Jonsson }
17638e96838SBengt Jonsson 
177a5023574SBill Pemberton int
17838e96838SBengt Jonsson ux500_regulator_debug_init(struct platform_device *pdev,
17938e96838SBengt Jonsson 	struct dbx500_regulator_info *regulator_info,
18038e96838SBengt Jonsson 	int num_regulators)
18138e96838SBengt Jonsson {
18238e96838SBengt Jonsson 	/* create directory */
18338e96838SBengt Jonsson 	rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
18438e96838SBengt Jonsson 	if (!rdebug.dir)
18538e96838SBengt Jonsson 		goto exit_no_debugfs;
18638e96838SBengt Jonsson 
18738e96838SBengt Jonsson 	/* create "status" file */
18838e96838SBengt Jonsson 	rdebug.status_file = debugfs_create_file("status",
18938e96838SBengt Jonsson 		S_IRUGO, rdebug.dir, &pdev->dev,
19038e96838SBengt Jonsson 		&ux500_regulator_status_fops);
19138e96838SBengt Jonsson 	if (!rdebug.status_file)
19238e96838SBengt Jonsson 		goto exit_destroy_dir;
19338e96838SBengt Jonsson 
19438e96838SBengt Jonsson 	/* create "power-state-count" file */
19538e96838SBengt Jonsson 	rdebug.power_state_cnt_file = debugfs_create_file("power-state-count",
19638e96838SBengt Jonsson 		S_IRUGO, rdebug.dir, &pdev->dev,
19738e96838SBengt Jonsson 		&ux500_regulator_power_state_cnt_fops);
19838e96838SBengt Jonsson 	if (!rdebug.power_state_cnt_file)
19938e96838SBengt Jonsson 		goto exit_destroy_status;
20038e96838SBengt Jonsson 
20138e96838SBengt Jonsson 	rdebug.regulator_array = regulator_info;
20238e96838SBengt Jonsson 	rdebug.num_regulators = num_regulators;
20338e96838SBengt Jonsson 
20438e96838SBengt Jonsson 	rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
20538e96838SBengt Jonsson 	if (!rdebug.state_before_suspend) {
20638e96838SBengt Jonsson 		dev_err(&pdev->dev,
20738e96838SBengt Jonsson 			"could not allocate memory for saving state\n");
20838e96838SBengt Jonsson 		goto exit_destroy_power_state;
20938e96838SBengt Jonsson 	}
21038e96838SBengt Jonsson 
21138e96838SBengt Jonsson 	rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
21238e96838SBengt Jonsson 	if (!rdebug.state_after_suspend) {
21338e96838SBengt Jonsson 		dev_err(&pdev->dev,
21438e96838SBengt Jonsson 			"could not allocate memory for saving state\n");
21538e96838SBengt Jonsson 		goto exit_free;
21638e96838SBengt Jonsson 	}
21738e96838SBengt Jonsson 
21838e96838SBengt Jonsson 	dbx500_regulator_testcase(regulator_info, num_regulators);
21938e96838SBengt Jonsson 	return 0;
22038e96838SBengt Jonsson 
22138e96838SBengt Jonsson exit_free:
22238e96838SBengt Jonsson 	kfree(rdebug.state_before_suspend);
22338e96838SBengt Jonsson exit_destroy_power_state:
22438e96838SBengt Jonsson 	debugfs_remove(rdebug.power_state_cnt_file);
22538e96838SBengt Jonsson exit_destroy_status:
22638e96838SBengt Jonsson 	debugfs_remove(rdebug.status_file);
22738e96838SBengt Jonsson exit_destroy_dir:
22838e96838SBengt Jonsson 	debugfs_remove(rdebug.dir);
22938e96838SBengt Jonsson exit_no_debugfs:
23038e96838SBengt Jonsson 	dev_err(&pdev->dev, "failed to create debugfs entries.\n");
23138e96838SBengt Jonsson 	return -ENOMEM;
23238e96838SBengt Jonsson }
23338e96838SBengt Jonsson 
2348dc995f5SBill Pemberton int ux500_regulator_debug_exit(void)
23538e96838SBengt Jonsson {
23638e96838SBengt Jonsson 	debugfs_remove_recursive(rdebug.dir);
23738e96838SBengt Jonsson 	kfree(rdebug.state_after_suspend);
23838e96838SBengt Jonsson 	kfree(rdebug.state_before_suspend);
23938e96838SBengt Jonsson 
24038e96838SBengt Jonsson 	return 0;
24138e96838SBengt Jonsson }
24238e96838SBengt Jonsson #endif
243