All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stanimir Varbanov <svarbanov@mm-sol.com>
To: Rajendra Nayak <rnayak@codeaurora.org>
Cc: sboyd@codeaurora.org, mturquette@linaro.org,
	linux-arm-msm@vger.kernel.org, georgi.djakov@linaro.org,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/6] clk: qcom: Add support for GDSCs
Date: Thu, 05 Mar 2015 14:47:14 +0200	[thread overview]
Message-ID: <54F85052.8090600@mm-sol.com> (raw)
In-Reply-To: <1425279749-16625-2-git-send-email-rnayak@codeaurora.org>

On 03/02/2015 09:02 AM, Rajendra Nayak wrote:
> From: Stephen Boyd <sboyd@codeaurora.org>
> 
> GDSCs (Global Distributed Switch Controllers) are responsible for
> safely collapsing and restoring power to peripherals in the SoC.
> These are best modelled as power domains using genpd and given
> the registers are scattered throughout the clock controller register
> space, its best to have the support added through the clock driver.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
>  drivers/clk/qcom/Kconfig  |   5 ++
>  drivers/clk/qcom/Makefile |   1 +
>  drivers/clk/qcom/gdsc.c   | 130 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/qcom/gdsc.h   |  43 +++++++++++++++
>  4 files changed, 179 insertions(+)
>  create mode 100644 drivers/clk/qcom/gdsc.c
>  create mode 100644 drivers/clk/qcom/gdsc.h
> 

<snip>

> --- /dev/null
> +++ b/drivers/clk/qcom/gdsc.c
> @@ -0,0 +1,130 @@
> +/*

<snip>

> +
> +#include "gdsc.h"
> +
> +#define PWR_ON_MASK		BIT(31)
> +#define EN_REST_WAIT_MASK	(0xF << 20)

you can use GENMASK(23, 20) here and below

> +#define EN_FEW_WAIT_MASK	(0xF << 16)
> +#define CLK_DIS_WAIT_MASK	(0xF << 12)
> +#define SW_OVERRIDE_MASK	BIT(2)
> +#define HW_CONTROL_MASK		BIT(1)
> +#define SW_COLLAPSE_MASK	BIT(0)
> +
> +/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
> +#define EN_REST_WAIT_VAL	(0x2 << 20)
> +#define EN_FEW_WAIT_VAL		(0x8 << 16)
> +#define CLK_DIS_WAIT_VAL	(0x2 << 12)
> +
> +#define TIMEOUT_US		100
> +
> +static int gdsc_is_enabled(struct gdsc *sc)
> +{
> +	u32 val;
> +
> +	regmap_read(sc->regmap, sc->gdscr, &val);

please, check the regmap_read for error, here and on few places below.

> +	return !!(val & PWR_ON_MASK);
> +}
> +
> +static int gdsc_toggle_logic(struct gdsc *sc, bool en)
> +{
> +	int ret;
> +	u32 val = en ? 0 : SW_COLLAPSE_MASK;
> +	u32 check = en ? PWR_ON_MASK : 0;
> +	unsigned long timeout;
> +
> +	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
> +	if (ret)
> +		return ret;
> +
> +	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
> +	do {
> +		regmap_read(sc->regmap, sc->gdscr, &val);
> +		if ((val & PWR_ON_MASK) == check)
> +			return 0;
> +	} while (time_before(jiffies, timeout));

blank line here will be better.

> +	regmap_read(sc->regmap, sc->gdscr, &val);
> +	if ((val & PWR_ON_MASK) == check)
> +		return 0;
> +
> +	pr_err("%s %s timed out\n", en ? "enabling" : "disabling", sc->pd.name);

use dev_err() or giving the error to the upper layers should be enough.

> +	return -ETIMEDOUT;
> +}
> +
> +static int gdsc_enable(struct generic_pm_domain *domain)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	int ret;
> +
> +	ret = gdsc_toggle_logic(sc, true);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * If clocks to this power domain were already on, they will take an
> +	 * additional 4 clock cycles to re-enable after the power domain is
> +	 * enabled. Delay to account for this. A delay is also needed to ensure
> +	 * clocks are not enabled within 400ns of enabling power to the
> +	 * memories.
> +	 */
> +	udelay(1);
> +
> +	return 0;
> +}
> +
> +static int gdsc_disable(struct generic_pm_domain *domain)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	int ret = 0;
> +
> +	ret = gdsc_toggle_logic(sc, false);
> +	if (ret)
> +		return ret;
> +
> +	return ret;

return gdsc_toggle_logic(sc, false);

> +}
> +
> +int gdsc_init(struct generic_pm_domain *domain, struct regmap *regmap)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	u32 mask;
> +	u32 val;
> +	int on;
> +
> +	sc->regmap = regmap;
> +
> +	/*
> +	 * Disable HW trigger: collapse/restore occur based on registers writes.
> +	 * Disable SW override: Use hardware state-machine for sequencing.
> +	 * Configure wait time between states.
> +	 */
> +	mask = HW_CONTROL_MASK | SW_OVERRIDE_MASK |
> +	       EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK;
> +	val = EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
> +	regmap_update_bits(sc->regmap, sc->gdscr, mask, val);
> +
> +	on = gdsc_is_enabled(sc);
> +
> +	pm_genpd_init(&sc->pd, NULL, !on);
> +	sc->pd.power_off = gdsc_disable;
> +	sc->pd.power_on = gdsc_enable;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(gdsc_init);

gdsc_init is used in common.c, no need to export it.

<snip>

-- 
regards,
Stan

WARNING: multiple messages have this Message-ID (diff)
From: svarbanov@mm-sol.com (Stanimir Varbanov)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 1/6] clk: qcom: Add support for GDSCs
Date: Thu, 05 Mar 2015 14:47:14 +0200	[thread overview]
Message-ID: <54F85052.8090600@mm-sol.com> (raw)
In-Reply-To: <1425279749-16625-2-git-send-email-rnayak@codeaurora.org>

On 03/02/2015 09:02 AM, Rajendra Nayak wrote:
> From: Stephen Boyd <sboyd@codeaurora.org>
> 
> GDSCs (Global Distributed Switch Controllers) are responsible for
> safely collapsing and restoring power to peripherals in the SoC.
> These are best modelled as power domains using genpd and given
> the registers are scattered throughout the clock controller register
> space, its best to have the support added through the clock driver.
> 
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
>  drivers/clk/qcom/Kconfig  |   5 ++
>  drivers/clk/qcom/Makefile |   1 +
>  drivers/clk/qcom/gdsc.c   | 130 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/qcom/gdsc.h   |  43 +++++++++++++++
>  4 files changed, 179 insertions(+)
>  create mode 100644 drivers/clk/qcom/gdsc.c
>  create mode 100644 drivers/clk/qcom/gdsc.h
> 

<snip>

> --- /dev/null
> +++ b/drivers/clk/qcom/gdsc.c
> @@ -0,0 +1,130 @@
> +/*

<snip>

> +
> +#include "gdsc.h"
> +
> +#define PWR_ON_MASK		BIT(31)
> +#define EN_REST_WAIT_MASK	(0xF << 20)

you can use GENMASK(23, 20) here and below

> +#define EN_FEW_WAIT_MASK	(0xF << 16)
> +#define CLK_DIS_WAIT_MASK	(0xF << 12)
> +#define SW_OVERRIDE_MASK	BIT(2)
> +#define HW_CONTROL_MASK		BIT(1)
> +#define SW_COLLAPSE_MASK	BIT(0)
> +
> +/* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
> +#define EN_REST_WAIT_VAL	(0x2 << 20)
> +#define EN_FEW_WAIT_VAL		(0x8 << 16)
> +#define CLK_DIS_WAIT_VAL	(0x2 << 12)
> +
> +#define TIMEOUT_US		100
> +
> +static int gdsc_is_enabled(struct gdsc *sc)
> +{
> +	u32 val;
> +
> +	regmap_read(sc->regmap, sc->gdscr, &val);

please, check the regmap_read for error, here and on few places below.

> +	return !!(val & PWR_ON_MASK);
> +}
> +
> +static int gdsc_toggle_logic(struct gdsc *sc, bool en)
> +{
> +	int ret;
> +	u32 val = en ? 0 : SW_COLLAPSE_MASK;
> +	u32 check = en ? PWR_ON_MASK : 0;
> +	unsigned long timeout;
> +
> +	ret = regmap_update_bits(sc->regmap, sc->gdscr, SW_COLLAPSE_MASK, val);
> +	if (ret)
> +		return ret;
> +
> +	timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
> +	do {
> +		regmap_read(sc->regmap, sc->gdscr, &val);
> +		if ((val & PWR_ON_MASK) == check)
> +			return 0;
> +	} while (time_before(jiffies, timeout));

blank line here will be better.

> +	regmap_read(sc->regmap, sc->gdscr, &val);
> +	if ((val & PWR_ON_MASK) == check)
> +		return 0;
> +
> +	pr_err("%s %s timed out\n", en ? "enabling" : "disabling", sc->pd.name);

use dev_err() or giving the error to the upper layers should be enough.

> +	return -ETIMEDOUT;
> +}
> +
> +static int gdsc_enable(struct generic_pm_domain *domain)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	int ret;
> +
> +	ret = gdsc_toggle_logic(sc, true);
> +	if (ret)
> +		return ret;
> +	/*
> +	 * If clocks to this power domain were already on, they will take an
> +	 * additional 4 clock cycles to re-enable after the power domain is
> +	 * enabled. Delay to account for this. A delay is also needed to ensure
> +	 * clocks are not enabled within 400ns of enabling power to the
> +	 * memories.
> +	 */
> +	udelay(1);
> +
> +	return 0;
> +}
> +
> +static int gdsc_disable(struct generic_pm_domain *domain)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	int ret = 0;
> +
> +	ret = gdsc_toggle_logic(sc, false);
> +	if (ret)
> +		return ret;
> +
> +	return ret;

return gdsc_toggle_logic(sc, false);

> +}
> +
> +int gdsc_init(struct generic_pm_domain *domain, struct regmap *regmap)
> +{
> +	struct gdsc *sc = domain_to_gdsc(domain);
> +	u32 mask;
> +	u32 val;
> +	int on;
> +
> +	sc->regmap = regmap;
> +
> +	/*
> +	 * Disable HW trigger: collapse/restore occur based on registers writes.
> +	 * Disable SW override: Use hardware state-machine for sequencing.
> +	 * Configure wait time between states.
> +	 */
> +	mask = HW_CONTROL_MASK | SW_OVERRIDE_MASK |
> +	       EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK;
> +	val = EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
> +	regmap_update_bits(sc->regmap, sc->gdscr, mask, val);
> +
> +	on = gdsc_is_enabled(sc);
> +
> +	pm_genpd_init(&sc->pd, NULL, !on);
> +	sc->pd.power_off = gdsc_disable;
> +	sc->pd.power_on = gdsc_enable;
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(gdsc_init);

gdsc_init is used in common.c, no need to export it.

<snip>

-- 
regards,
Stan

  reply	other threads:[~2015-03-05 12:47 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-02  7:02 [PATCH 0/6] Add support for QCOM GDSCs Rajendra Nayak
2015-03-02  7:02 ` Rajendra Nayak
2015-03-02  7:02 ` [PATCH 1/6] clk: qcom: Add support for GDSCs Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-05 12:47   ` Stanimir Varbanov [this message]
2015-03-05 12:47     ` Stanimir Varbanov
2015-03-02  7:02 ` [PATCH 2/6] clk: qcom: gdsc: Prepare common clk probe to register gdscs Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-05 12:47   ` Stanimir Varbanov
2015-03-05 12:47     ` Stanimir Varbanov
2015-03-02  7:02 ` [PATCH 3/6] clk: qcom: gdsc: Add GDSCs in msm8916 GCC Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-02  7:02 ` [PATCH 4/6] clk: qcom: gdsc: Add GDSCs in msm8974 GCC Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-02  7:02 ` [PATCH 5/6] clk: qcom: gdsc: Add GDSCs in msm8974 MMCC Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-02  7:02 ` [PATCH 6/6] clk: qcom: gdsc: Add GDSCs in apq8084 GCC Rajendra Nayak
2015-03-02  7:02   ` Rajendra Nayak
2015-03-05 16:55 ` [PATCH 0/6] Add support for QCOM GDSCs Stanimir Varbanov
2015-03-05 16:55   ` Stanimir Varbanov
2015-03-06  4:31   ` Rajendra Nayak
2015-03-06  4:31     ` Rajendra Nayak

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=54F85052.8090600@mm-sol.com \
    --to=svarbanov@mm-sol.com \
    --cc=georgi.djakov@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=mturquette@linaro.org \
    --cc=rnayak@codeaurora.org \
    --cc=sboyd@codeaurora.org \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.