From patchwork Fri Feb 26 02:38:29 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pankaj Dev X-Patchwork-Id: 62918 Delivered-To: patch@linaro.org Received: by 10.112.199.169 with SMTP id jl9csp496674lbc; Thu, 25 Feb 2016 19:24:24 -0800 (PST) X-Received: by 10.98.17.129 with SMTP id 1mr68297844pfr.30.1456457064763; Thu, 25 Feb 2016 19:24:24 -0800 (PST) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id f86si16649380pfd.208.2016.02.25.19.24.24; Thu, 25 Feb 2016 19:24:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=devicetree-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1750767AbcBZDYW (ORCPT + 6 others); Thu, 25 Feb 2016 22:24:22 -0500 Received: from mx07-00178001.pphosted.com ([62.209.51.94]:50560 "EHLO mx07-00178001.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750736AbcBZDYV (ORCPT ); Thu, 25 Feb 2016 22:24:21 -0500 Received: from pps.filterd (m0046668.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.15.0.59/8.15.0.59) with SMTP id u1Q3JsMY002457; Fri, 26 Feb 2016 04:23:48 +0100 Received: from beta.dmz-ap.st.com (beta.dmz-ap.st.com [138.198.100.35]) by mx07-00178001.pphosted.com with ESMTP id 21ac4crq62-1 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-SHA bits=256 verify=NOT); Fri, 26 Feb 2016 04:23:48 +0100 Received: from zeta.dmz-ap.st.com (ns6.st.com [138.198.234.13]) by beta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 395814C; Fri, 26 Feb 2016 03:23:43 +0000 (GMT) Received: from Webmail-ap.st.com (eapex1hubcas1.st.com [10.80.176.8]) by zeta.dmz-ap.st.com (STMicroelectronics) with ESMTP id 4707A65; Fri, 26 Feb 2016 03:23:42 +0000 (GMT) Received: from localhost (10.199.12.234) by Webmail-ap.st.com (10.80.176.7) with Microsoft SMTP Server (TLS) id 8.3.406.0; Fri, 26 Feb 2016 11:23:41 +0800 From: Pankaj Dev To: , CC: , , , , , , , Subject: [RFC v1] clk: Add debugfs nodes for enable/disable/set-rate/set-parent Date: Fri, 26 Feb 2016 08:08:29 +0530 Message-ID: <1456454309-25037-1-git-send-email-pankaj.dev@st.com> X-Mailer: git-send-email 1.7.5.4 MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2016-02-26_03:, , signatures=0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org To enhance debug interface for clocks, we add the following interfaces to the clock nodes created at /sys/kernel/debug/clk/CLOCK_NAME 1. clk_set_rate : Set new rate to value. Reading returns the current rate 2. clk_set_parent : Set new parent to parent-name. Reading returns the current parent 3. clk_prepare_enable : Call clk_prepare_enable X times, X is the input value 4. clk_disable_unprepare : Call clk_disable_unprepare X times, X is the input value This is particularly useful during SoC bring-up phase, and also when drivers want to verify if some issue is caused by clocks turning off at wrong moments. Signed-off-by: Pankaj Dev --- drivers/clk/clk.c | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 143 insertions(+), 0 deletions(-) -- 1.7.5.4 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index cbc72a1..aa08023 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "clk.h" @@ -348,6 +349,128 @@ static const struct file_operations clk_dump_fops = { .release = single_release, }; +/* Debugfs set_rate entry */ +static int clk_debug_rate_get(void *data, u64 *rate) +{ + struct clk_core *c = data; + + *rate = clk_get_rate(c->hw->clk); + + return 0; +} + +static int clk_debug_rate_set(void *data, u64 rate) +{ + struct clk_core *c = data; + + return clk_set_rate(c->hw->clk, rate); +} + +DEFINE_SIMPLE_ATTRIBUTE(clk_debug_rate_fops, clk_debug_rate_get, + clk_debug_rate_set, "%lld\n"); + +/* Debugfs prepare_enable entry */ +static int clk_debug_prep_enable(void *data, u64 count) +{ + struct clk_core *c = data; + int i, ret = 0; + + for (i = 0; i < count; i++) { + ret = clk_prepare_enable(c->hw->clk); + if (ret) + return ret; + } + + return ret; +} + +DEFINE_SIMPLE_ATTRIBUTE(clk_debug_prep_enable_fops, NULL, + clk_debug_prep_enable, "%lld\n"); + +/* Debugfs disable_unprepare entry */ +static int clk_debug_disable_unprep(void *data, u64 count) +{ + struct clk_core *c = data; + int i; + + for (i = 0; i < count; i++) + clk_disable_unprepare(c->hw->clk); + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(clk_debug_disable_unprep_fops, NULL, + clk_debug_disable_unprep, "%lld\n"); + +/* Debugfs set_parent entry */ +static int clk_debug_parent_get(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct clk_core *c = file->private_data; + struct clk *p; + int ret; + + if (*ppos) /* continued read */ + return 0; + + p = clk_get_parent(c->hw->clk); + count = min(strlen(__clk_get_name(p)), count); + + ret = copy_to_user(user_buf, __clk_get_name(p), count); + if (ret) { + pr_err("%s: error reading data\n", __func__); + return -EINVAL; + } + + /* Add \n */ + ret = copy_to_user(user_buf + count, "\n", 1); + if (ret) { + pr_err("%s: error reading data\n", __func__); + return -EINVAL; + } + count++; + + *ppos += count; + + return count; +} + +static int clk_debug_parent_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct clk_core *c = file->private_data; + struct clk *p; + char pname[50]; /* 50 char shud be enough for clock name + \0 */ + int ret; + + count = min(sizeof(pname), count); + strncpy_from_user(pname, user_buf, count); + pname[count - 1] = 0; /* NULL terminate */ + + p = __clk_lookup(pname); + if (!p) { + pr_err("%s: %s not found\n", __func__, pname); + return -EINVAL; + } + + ret = clk_set_parent(c->hw->clk, p); + if (ret) { + pr_err("%s: %s Incorrect Argument\n", __func__, pname); + return -EINVAL; + } + + return count; +} + +static const struct file_operations clk_debug_parent_fops = { + .open = simple_open, + .read = clk_debug_parent_get, + .write = clk_debug_parent_set, +}; + +/* caller must hold prepare_lock */ static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry) { struct dentry *d; @@ -405,6 +528,26 @@ static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry) goto err_out; } + d = debugfs_create_file("clk_set_rate", S_IRUGO | S_IWUSR, clk->dentry, + clk, &clk_debug_rate_fops); + if (!d) + goto err_out; + + d = debugfs_create_file("clk_set_parent", S_IRUGO | S_IWUSR, + clk->dentry, clk, &clk_debug_parent_fops); + if (!d) + goto err_out; + + d = debugfs_create_file("clk_prepare_enable", S_IWUSR, clk->dentry, + clk, &clk_debug_prep_enable_fops); + if (!d) + goto err_out; + + d = debugfs_create_file("clk_disable_unprepare", S_IWUSR, clk->dentry, + clk, &clk_debug_disable_unprep_fops); + if (!d) + goto err_out; + ret = 0; goto out;