From: Subhash Jadavani <subhashj@codeaurora.org>
To: Sujit Reddy Thumma <sthumma@codeaurora.org>
Cc: Vinayak Holikatti <vinholikatti@gmail.com>,
Santosh Y <santoshsy@gmail.com>,
"James E.J. Bottomley" <JBottomley@parallels.com>,
linux-scsi@vger.kernel.org, devicetree@vger.kernel.org,
linux-arm-msm@vger.kernel.org
Subject: Re: [PATCH V2 3/3] scsi: ufs: Add clock initialization support
Date: Tue, 27 Aug 2013 13:47:51 +0530 [thread overview]
Message-ID: <521C60AF.9030009@codeaurora.org> (raw)
In-Reply-To: <1377577093-10068-4-git-send-email-sthumma@codeaurora.org>
Looks good to me.
Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org>
On 8/27/2013 9:48 AM, Sujit Reddy Thumma wrote:
> Add generic clock initialization support for UFSHCD platform
> driver. The clock info is read from device tree using standard
> clock bindings. A generic max-clock-frequency-hz property is
> defined to save information on maximum operating clock frequency
> the h/w supports.
>
> Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
> ---
> .../devicetree/bindings/ufs/ufshcd-pltfrm.txt | 15 +++-
> drivers/scsi/ufs/ufshcd-pltfrm.c | 71 +++++++++++++++++
> drivers/scsi/ufs/ufshcd.c | 89 +++++++++++++++++++++-
> drivers/scsi/ufs/ufshcd.h | 18 +++++
> 4 files changed, 190 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> index 65e3117..b0f791a 100644
> --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
> @@ -21,8 +21,17 @@ Optional properties:
> - vccq-max-microamp : specifies max. load that can be drawn from vccq supply
> - vccq2-max-microamp : specifies max. load that can be drawn from vccq2 supply
>
> +- clocks : List of phandle and clock specifier pairs
> +- clock-names : List of clock input name strings sorted in the same
> + order as the clocks property.
> +- max-clock-frequency-hz : List of maximum operating frequency stored in the same
> + order as the clocks property. If this property is not
> + defined or a value in the array is "0" then it is assumed
> + that the frequency is set by the parent clock or a
> + fixed rate clock source.
> +
> Note: If above properties are not defined it can be assumed that the supply
> -regulators are always on.
> +regulators or clocks are always on.
>
> Example:
> ufshc@0xfc598000 {
> @@ -37,4 +46,8 @@ Example:
> vcc-max-microamp = 500000;
> vccq-max-microamp = 200000;
> vccq2-max-microamp = 200000;
> +
> + clocks = <&core 0>, <&ref 0>, <&iface 0>;
> + clock-names = "core_clk", "ref_clk", "iface_clk";
> + max-clock-frequency-hz = <100000000 19200000 0>;
> };
> diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
> index cbdf5f3..15c8086 100644
> --- a/drivers/scsi/ufs/ufshcd-pltfrm.c
> +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
> @@ -52,6 +52,71 @@ static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
> return NULL;
> }
>
> +static int ufshcd_parse_clock_info(struct ufs_hba *hba)
> +{
> + int ret = 0;
> + int cnt;
> + int i;
> + struct device *dev = hba->dev;
> + struct device_node *np = dev->of_node;
> + char *name;
> + u32 *clkfreq = NULL;
> + struct ufs_clk_info *clki;
> +
> + if (!np)
> + goto out;
> +
> + INIT_LIST_HEAD(&hba->clk_list_head);
> +
> + cnt = of_property_count_strings(np, "clock-names");
> + if (!cnt || (cnt == -EINVAL)) {
> + dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
> + __func__);
> + } else if (cnt < 0) {
> + dev_err(dev, "%s: count clock strings failed, err %d\n",
> + __func__, cnt);
> + ret = cnt;
> + }
> +
> + if (cnt <= 0)
> + goto out;
> +
> + clkfreq = kzalloc(cnt * sizeof(*clkfreq), GFP_KERNEL);
> + if (!clkfreq) {
> + ret = -ENOMEM;
> + dev_err(dev, "%s: memory alloc failed\n", __func__);
> + goto out;
> + }
> +
> + ret = of_property_read_u32_array(np,
> + "max-clock-frequency-hz", clkfreq, cnt);
> + if (ret && (ret != -EINVAL)) {
> + dev_err(dev, "%s: invalid max-clock-frequency-hz property, %d\n",
> + __func__, ret);
> + goto out;
> + }
> +
> + for (i = 0; i < cnt; i++) {
> + ret = of_property_read_string_index(np,
> + "clock-names", i, (const char **)&name);
> + if (ret)
> + goto out;
> +
> + clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
> + if (!clki) {
> + ret = -ENOMEM;
> + goto out;
> + }
> +
> + clki->max_freq = clkfreq[i];
> + clki->name = kstrdup(name, GFP_KERNEL);
> + list_add_tail(&clki->list, &hba->clk_list_head);
> + }
> +out:
> + kfree(clkfreq);
> + return ret;
> +}
> +
> #define MAX_PROP_SIZE 32
> static int ufshcd_populate_vreg(struct device *dev, const char *name,
> struct ufs_vreg **out_vreg)
> @@ -265,6 +330,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
>
> hba->vops = get_variant_ops(&pdev->dev);
>
> + err = ufshcd_parse_clock_info(hba);
> + if (err) {
> + dev_err(&pdev->dev, "%s: clock parse failed %d\n",
> + __func__, err);
> + goto out;
> + }
> err = ufshcd_parse_regulator_info(hba);
> if (err) {
> dev_err(&pdev->dev, "%s: regulator init failed %d\n",
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index e520b15..61c6e54 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -2983,6 +2983,80 @@ out:
> return ret;
> }
>
> +static int ufshcd_setup_clocks(struct ufs_hba *hba, bool on)
> +{
> + int ret = 0;
> + struct ufs_clk_info *clki;
> + struct list_head *head = &hba->clk_list_head;
> +
> + if (!head || list_empty(head))
> + goto out;
> +
> + list_for_each_entry(clki, head, list) {
> + if (!IS_ERR_OR_NULL(clki->clk)) {
> + if (on && !clki->enabled) {
> + ret = clk_prepare_enable(clki->clk);
> + if (ret) {
> + dev_err(hba->dev, "%s: %s prepare enable failed, %d\n",
> + __func__, clki->name, ret);
> + goto out;
> + }
> + } else if (!on && clki->enabled) {
> + clk_disable_unprepare(clki->clk);
> + }
> + clki->enabled = on;
> + dev_dbg(hba->dev, "%s: clk: %s %sabled\n", __func__,
> + clki->name, on ? "en" : "dis");
> + }
> + }
> +out:
> + if (ret) {
> + list_for_each_entry(clki, head, list) {
> + if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled)
> + clk_disable_unprepare(clki->clk);
> + }
> + }
> + return ret;
> +}
> +
> +static int ufshcd_init_clocks(struct ufs_hba *hba)
> +{
> + int ret = 0;
> + struct ufs_clk_info *clki;
> + struct device *dev = hba->dev;
> + struct list_head *head = &hba->clk_list_head;
> +
> + if (!head || list_empty(head))
> + goto out;
> +
> + list_for_each_entry(clki, head, list) {
> + if (!clki->name)
> + continue;
> +
> + clki->clk = devm_clk_get(dev, clki->name);
> + if (IS_ERR(clki->clk)) {
> + ret = PTR_ERR(clki->clk);
> + dev_err(dev, "%s: %s clk get failed, %d\n",
> + __func__, clki->name, ret);
> + goto out;
> + }
> +
> + if (clki->max_freq) {
> + ret = clk_set_rate(clki->clk, clki->max_freq);
> + if (ret) {
> + dev_err(hba->dev, "%s: %s clk set rate(%dHz) failed, %d\n",
> + __func__, clki->name,
> + clki->max_freq, ret);
> + goto out;
> + }
> + }
> + dev_dbg(dev, "%s: clk: %s, rate: %lu\n", __func__,
> + clki->name, clk_get_rate(clki->clk));
> + }
> +out:
> + return ret;
> +}
> +
> static int ufshcd_variant_hba_init(struct ufs_hba *hba)
> {
> int err = 0;
> @@ -3042,14 +3116,22 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
> {
> int err;
>
> - err = ufshcd_init_vreg(hba);
> + err = ufshcd_init_clocks(hba);
> if (err)
> goto out;
>
> - err = ufshcd_setup_vreg(hba, true);
> + err = ufshcd_setup_clocks(hba, true);
> if (err)
> goto out;
>
> + err = ufshcd_init_vreg(hba);
> + if (err)
> + goto out_disable_clks;
> +
> + err = ufshcd_setup_vreg(hba, true);
> + if (err)
> + goto out_disable_clks;
> +
> err = ufshcd_variant_hba_init(hba);
> if (err)
> goto out_disable_vreg;
> @@ -3058,6 +3140,8 @@ static int ufshcd_hba_init(struct ufs_hba *hba)
>
> out_disable_vreg:
> ufshcd_setup_vreg(hba, false);
> +out_disable_clks:
> + ufshcd_setup_clocks(hba, false);
> out:
> return err;
> }
> @@ -3066,6 +3150,7 @@ static void ufshcd_hba_exit(struct ufs_hba *hba)
> {
> ufshcd_variant_hba_exit(hba);
> ufshcd_setup_vreg(hba, false);
> + ufshcd_setup_clocks(hba, false);
> }
>
> /**
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index f66e58c..1e91687 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -155,6 +155,22 @@ struct ufs_dev_cmd {
> struct ufs_query query;
> };
>
> +/**
> + * struct ufs_clk_info - UFS clock related info
> + * @list: list headed by hba->clk_list_head
> + * @clk: clock node
> + * @name: clock name
> + * @max_freq: maximum frequency supported by the clock
> + * @enabled: variable to check against multiple enable/disable
> + */
> +struct ufs_clk_info {
> + struct list_head list;
> + struct clk *clk;
> + const char *name;
> + u32 max_freq;
> + bool enabled;
> +};
> +
> #define PRE_CHANGE 0
> #define POST_CHANGE 1
> /**
> @@ -220,6 +236,7 @@ struct ufs_hba_variant_ops {
> * @dev_cmd: ufs device management command information
> * @auto_bkops_enabled: to track whether bkops is enabled in device
> * @vreg_info: UFS device voltage regulator information
> + * @clk_list_head: UFS host controller clocks list node head
> */
> struct ufs_hba {
> void __iomem *mmio_base;
> @@ -279,6 +296,7 @@ struct ufs_hba {
>
> bool auto_bkops_enabled;
> struct ufs_vreg_info vreg_info;
> + struct list_head clk_list_head;
> };
>
> #define ufshcd_writel(hba, val, reg) \
prev parent reply other threads:[~2013-08-27 8:17 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-27 4:18 [PATCH V2 0/3] scsi: ufs: Add support for clock and regulator initializaiton Sujit Reddy Thumma
2013-08-27 4:18 ` [PATCH V2 1/3] scsi: ufs: Allow vendor specific initialization Sujit Reddy Thumma
2013-08-27 8:17 ` Subhash Jadavani
2013-08-29 17:30 ` Santosh Y
2013-09-09 11:33 ` Seungwon Jeon
[not found] ` <000901cead50$573ede90$05bc9bb0$%jun-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
2013-09-19 11:27 ` Sujit Reddy Thumma
2013-08-27 4:18 ` [PATCH V2 2/3] scsi: ufs: Add regulator enable support Sujit Reddy Thumma
2013-08-27 8:17 ` Subhash Jadavani
2013-08-29 17:39 ` Santosh Y
2013-08-27 4:18 ` [PATCH V2 3/3] scsi: ufs: Add clock initialization support Sujit Reddy Thumma
2013-08-27 8:17 ` Subhash Jadavani [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=521C60AF.9030009@codeaurora.org \
--to=subhashj@codeaurora.org \
--cc=JBottomley@parallels.com \
--cc=devicetree@vger.kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=santoshsy@gmail.com \
--cc=sthumma@codeaurora.org \
--cc=vinholikatti@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).