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